J2ME Java

/*
 * Copyright (c) 2000-2001 Sun Microsystems, Inc. All Rights Reserved.
 */
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
/**
 * A MIDlet that displays the Doggy animation.
 *
 * @author Mark A. Patel - Motorola, Inc.
 * @author Roger Riggs - Sun Microsystems, Inc.
 **/
public class DoggyMIDlet extends MIDlet implements CommandListener {
    Command cmdExit;
    /**
     * Constructs a new DoggyMIDlet
     **/
    public DoggyMIDlet() {
        cmdExit = new Command("Exit", Command.EXIT, 1);
    }
    
    /**
     * Starts the app by creating a new Doggy instance and displaying it
     **/
    protected void startApp() throws MIDletStateChangeException {
        Doggy d;
        d = new Doggy();
        d.addCommand(cmdExit);
        d.setCommandListener(this);
        
        Display.getDisplay(this).setCurrent(d);
  
    }
    
    protected void pauseApp() {
    }
    
    protected void destroyApp(boolean unconditional)
  throws MIDletStateChangeException {
    }
    
    public void commandAction(Command c, Displayable d) {
        if (c == cmdExit) {
            try {
                destroyApp(false);
            } catch (Exception e) {}
            notifyDestroyed();
        }
    }
}
 class Doggy extends Canvas implements Runnable {
  /**
   * Number of frames in the animation
   **/
  static final int FRAME_COUNT = 17;
  /**
   * Normal frame delay (milliseconds)
   **/
  static final int FRAME_DELAY = 180;
  /**
   * Frame delay for the last frame where the dog is sleeping
   **/
  static final int LAST_FRAME_DELAY = 3000;
  /**
   * Relative horizontal position where each of the frames 
   * should be rendered. 0 represents the left edge of the screen
   * and 1024 represents the right edge of the run distance 
   * (1024 is used so that scaling can be performed using
   * simple bit shifts instead of division operations). 
   **/
  static final int[] framePositions = {
    0, 50, 186, 372, 558, 744, 930, 1024, 1024,
    834, 651, 465, 279, 93, 0, 0, 0
  };
  /**
   * An Image containing the 17 frames of the dog running,
   * stacked vertically.
   * Using a single image is much more efficient than using several 
   * images with each containing a single frame.
   * Each frame can be rendered seperately by setting the clip 
   * region to the size of a single frame and then
   * rendering the image at the correct position so that the desired 
   * frame isaligned with the clip region.
   **/
  Image doggyImages = null;
  /**
   * Width of a single animation frame
   **/
  int frameWidth = 0;
  /**
   * Height of a single animation frame
   **/
  int frameHeight = 0;
  /**
   * Index of the current frame
   **/
  int frameIndex = 0;
  /**
   * The distance, in pixels, that the dog can run (screen width less
   * the width of a single frame)
   **/
  int runLength = 0;
  /**
   * Indicates if the animation is currently running
   **/
  boolean running = false;
  /**
   * Called when this Canvas is shown.  This method starts the timer 
   * that runs the animation sequence.
   **/
  protected void showNotify() {
    if (doggyImages == null) {
      try {
        doggyImages =
          Image.createImage("/examples/animation/Doggy.png");
        frameWidth = doggyImages.getWidth();
        frameHeight = doggyImages.getHeight() / FRAME_COUNT;
      } catch (Exception ioe) {
        return; // no image to animate
      }
    }
    runLength = getWidth() - frameWidth;
    running = true;
    frameIndex = 0;
    new Thread(this).start();
  }
  /**
   * Called when this Canvas is hidden.  This method stops the
   * animation timer to free up processing
   * power while this Canvas is not showing.
   **/
  protected void hideNotify() {
    running = false;
  }
  public void run() {
    // Need to catch InterruptedExceptions and bail if one occurs
    try {
      while (running) {
        Thread.sleep((frameIndex == FRAME_COUNT - 1) ?
               LAST_FRAME_DELAY : FRAME_DELAY);
        // Remember the last frame index so we can compute
        // the repaint region
        int lastFrameIndex = frameIndex;
        // Update the frame index
        frameIndex = (frameIndex + 1) % FRAME_COUNT;
        // Determine the left edge of the repaint region
        int repaintLeft = framePositions[lastFrameIndex];
        int repaintRight = framePositions[frameIndex];
        if (framePositions[lastFrameIndex] > framePositions[frameIndex]) {
          repaintLeft = framePositions[frameIndex];
          repaintRight = framePositions[lastFrameIndex];
        }
        // Scale the repaint coordinates to the width of the screen
        repaintLeft = (repaintLeft * runLength) >> 10;
        repaintRight = (repaintRight * runLength) >> 10;
        // Trigger a repaint of the affected portion of the screen
        // Repaint the region where the last frame was rendered
        // (ensures that it is cleared)
        repaint(repaintLeft, 0,
            frameWidth + repaintRight - repaintLeft, frameHeight);
      }
    } catch (InterruptedException e) {}
  }
  public void paint(Graphics g) {
    // Clear the background (fill with white)     
    // The clip region will limit the area that
    // actually gets cleared to save time
    g.setColor(0xFFFFFF);
    g.fillRect(0, 0, getWidth(), getHeight());
    // Translate the graphics to the appropriate
    // position for the current frame
    g.translate((framePositions[frameIndex] * runLength) >> 10, 0);
    // Constrain the clip region to the size of a single frame
    g.clipRect(0, 0, frameWidth, frameHeight);
    // Draw the current frame by drawing the entire image with
    // the appropriate vertical offset so that the desired frame
    // lines up with the clip region.
    g.drawImage(doggyImages, 0, -(frameIndex * frameHeight),
          Graphics.LEFT + Graphics.TOP);
  }
}