www.pudn.com > j2mewireless_examples.zip > Doggy.java


/*
 * Copyright (c) 2000-2001 Sun Microsystems, Inc. All Rights Reserved.
 */

package examples.animation;

import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Image;

/**
 * This Canvas subclass demonstrates how to create a simple animation
 * sequence using the MIDP graphics API's.
 *
 * @author Mark A. Patel - Motorola, Inc.
 * @author Roger Riggs - Sun Microsystems, Inc.
 **/
public 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);
	}
}