Animating images in midp

xiaoxiao2021-03-06  75

By Eric Giguerejune 6, 2002Download: [Source Code Zip] Running The Example

Developers using the Mobile Information Device Profile (MIDP) often ask how they can get a MIDlet to display animated images. MIDP 1.0 provides no direct support for animated images (the MIDP 2.0 specification, still in development, does), but it's not that hard To do it yourself.

The basic premise of any animation is to draw separate images quickly enough that the human eye sees movement. The images must of course be drawn in sequence, and the smaller the changes from one image to the next the better.

The first thing to do, then, is to use your favorite painting application to create a series of identically-sized images to compose the animation Each separate image represents a different frame of the animation You will need several frames -.. The more frames . ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

There are two ways to make the images available to the MIDlet that is going to animate them. One way is to place them on a web server and have the MIDlet download them using MIDP's built-in HTTP support. The simpler way, however, is To package the with the midlet in it 's Jar File. if're Using The J2ME Wireless Toolkit, Just Place The PNG Files in Your Project's Reside.

Animation is mostly a matter of bookkeeping:. Keeping track of the current frame and advancing to the next frame as appropriate It makes sense to use a class to do the housekeeping for you, so define an AnimatedImage class:

Import java.util. *;

Import javax.microedition.lcdui. *;

// defines An animated image, Which is Just a set // of images of equag size shich area

// TO Simulate Movement.

Public class AnimatedImage Extends Timertask {

Private Canvas Canvas;

PRIVATE [] ]MAGES;

Private int [] [] cliplist;

Private int current;

Private int x;

PRIVATE INT Y;

Private int W;

Private int h;

// Construct an animation with no canvas.

Public AnimatedImage (image []) {

THIS (NULL, IMAGES, NULL);

}

// Construct an animation with a null clip list.

Public AnimatedImage (Canvas Canvas, Image []

{THIS (canvas, images, null);

}

// construct an animation. The Canvas Can Be Null,

// But if not null the a repaint will be triggered

// on it each time the Image change Due to a Timer

// Event. if a clip list isot, the image is

// DRAWN MULTIPLE TIMES, EACH TIME WITH A DIFFERENT

// Clip Rectangle, To Simulate Transparent Parts.

Public AnimatedImage (Canvas Canvas, Image ",

int [] cliplist) {

THIS.CANVAS = Canvas;

..

THIS.CLIPLIST = CLIPLIST;

IF (images! = null && cliplist! = NULL) {

IF (Cliplist.Length

Throw new illegalargumentException ();

}

}

IF (images! = null && images.length> 0) {

W = images [0] .GetWidth ();

H = images [0] .getHeight ();

}

}

//Move to the next frame, wrapping if necessary.

Public void advance (boolean repaint) {

IF ( Current> = images.length) {

CURRENT = 0;

}

IF (Repaint && Canvas! = null && canvas.isshown ()

) {

Canvas.Repaint (x, y, w, h);

Canvas.ServiceRepaints ();

}

}

// Draw the current image in the animation. IF

// No Clip List, Just A Simple Copy, OtherWise // Set The Clipping Rectangle Accordingly and

// Draw the Image Multiple Times.

Public Void Draw (Graphics G) {

IF (w == 0 || h == 0) return;

INT which = current;

IF (CLIPLIST == Null || CLIPLIST [Which] == NULL

) {

g.drawimage (images [Which], X, Y,

G.top | g.Left);

} else {

INT CX = g.getClipx ();

INT CY = g.getClipy ();

INT CW = g.getClipwidth ();

INT CH = g.getclipheight ();

int [] list = cliplist [which];

For (int i = 0; i 3 <= list.length; i =

4) {

G.setClip (x list [0], y list [1],

List [2], list [3]);

g.drawimage (images [Which], X, Y,

G.top | g.Left);

}

G.SETCLIP (CX, CY, CW, CH);

}

}

// Moves the animation's top left corner.

Public void move (int x, int y) {

THIS.X = X;

THIS.Y = Y;

}

// invoked by the time. Advances to the next frame

// and causes a repaint if a canvas isot specified.

Public void run () {

IF (w == 0 || h == 0) return;

Advance (True);

}

}

When you instantiate AnimatedImage you pass the constructor an array of Image objects representing the individual animation frames The images are assumed to be of identical height and width Use the Image.createImage () method to load an image from the JAR file..:

Private image [] loadframes (string name, int frames)

THROWS IOEXCEPTION {

Image [] images = new image [frames];

For (int i = 0; i

Images [i] = image.createImage (Name i

".png");

}

Return images;

}

For Example, To Load The Series of Frames Stored As /Images/bird0.png, /images/bird1.png, and so on through /images/bird6.png, and the create an animate, use: image [] frames = LoadFrames ("/ Images / bird", 7);

AnimatedImage Ai = New AnimatedImage (frames);

Ai.move (20, 20); // set top-left to 20, 20

Note That An animatedimage Keeps TRACK OF ITS POSITION AND Draws Itself relative to That position.

You can also pass in an optional Canvas instance and an optional clip list. If you specify a canvas and use a timer to advance the animation to the next frame automatically, as in the next code sample, the canvas is automatically repainted after the advance. This Behavior Is Completely Optional, However - The Application Can Also Choose When To Repaint.

Because MIDP 1.0 does not support image transparency, the AnimatedImage class simulates it using a clip list, a set of rectangular areas within the image. The image is drawn multiple times, each time with the clipping region set to one of the areas in the clip . list The clip list is specified on a per-frame basis, so you need to create an array of integers for each frame of the image The array size is a multiple of four, because each clipping area consists of four values:. the left coordinate, the top coordinate, the width, and the height. The coordinate values ​​are relative to the top left corner of the image. Note that using a clip list slows down the animation. For complex images you may prefer to use vector graphics to do The Drawing.

The AnimatedImage class extends java.util.TimerTask, which allows you to schedule it with a timer A previous Tech Tip discussed how to use timers in detail Here's an example of using one for animation..:

Timer Timer = New Timer (); AnimatedImage Ai = ..... // get the image

Timer.schedule (AI, 200, 200);

Every 200 Milliseconds or So, The Timer Invokes The AnimatedImage.Run () Method, Which Causes The Animation To Move To The Next Frame. The Animation Also Repaints Itself if A canvas is available.

All we need now is a midlet to try out the animation. We define a Simple Extension of Canvas That Lets US "Attach" Animated images to it:

Import java.util. *;

Import javax.microedition.lcdui. *;

// a canvas to which you can attach one or more

// animated images. when the canvas is painted,

// IT cycles through the animated images and asks

// Them to Paint Their Current Image.

Public class animatedcanvas extends canvas {

Private display display;

PRIVATE OFFSCREEN

Private vector images = new vector ();

Public Animatedcanvas (Display Display) {

this.display = display;

// if the canvas is not double buffered by the

// System, Do It Ourslves ...

IF (! isdoublebuffered ()) {

OFFSCREEN = image.createImage (getWidth (),

GetHeight ());

}

}

// add an animated image to the list.

Public Void Add (AnimatedImage Image) {

Images.addelement (image);

}

// Paint the canvas by Erasing the screen and then

// Painting Each Animated Image in Turn. Double

// buffering is buy to reduce flicker.

Protected Void Paint (Graphics G) {

Graphics saved = g;

IF (offscreen! = null) {

g = OFFSCREEN.GRAPHES ();

}

G.SetColor (255, 255, 255);

G.fillRect (0, 0, getWidth (), getHeight ());

INT N = images.size ();

For (int i = 0; i

AnimatedImage IMG = (AnimatedImage)

Images.ementat (i);

Img.draw (g);

}

IF (g! = saved) {

Saved.drawImage (offscreen, 0, 0, graphics.LRAPHICS.TOP);

}

}

}

The code for the AnimatedCanvas class is quite simple, consisting of an animation registration method and a paint method. Every time the canvas is painted, it erases its background, then cycles through the list of registered animations, directing each to draw itself. Notice that The Class Uses Double Buffering to Reduce Flicker (An Earlier Tech Tip Discussed Double Buffering).

Import java.io. *;

Import java.util. *;

Import javax.microedition.lcdui. *;

Import javax.microedition.midlet. *;

// MIDlet That Displays Some Simple Animation.

// Displays a series of birds on the screen and

// Animates Them At Different (Random) Rates.

Public Class AnimationTest Extends MIDLET

Implements commandListener {

Private static final int bird_frames = 7;

Private statin final int num_birds = 5;

Private display display;

Private Timer Timer = New Timer ();

Private animatedimage [] birds;

PRIVATE RANDOM = New Random ();

Public static factory command exitcommand =

New Command ("exit",

Command.exit, 1);

Public animationtest () {

}

Public void CommandAction (Command C,

Displayable d) {

IF (c == EXITCOMMAND) {

exitmidlet ();

}

}

Protected Void DestroyApp (Boolean Unconditional)

Throws MidletStateChangeException {

exitmidlet ();

}

Public void exitmidlet () {

Timer.cancel (); // Turn IT Off ...

NotifyDestroyed ();

}

// generate a non-negative random number ...

Private int genrandom (int UPPER) {

Return (math.abs (random.nextint ())% UPPER);

}

Public Display getDisplay () {Return Display;

// Initialize Things by Creating the Canvas and Then

// Creating a series of birds That Are Moved to // Random Locations on the Canvas and Attached To

// a Timer for scheduling.

protected void initmidlet () {

Try {

AnimatedCanvas C = New

AnimatedCanvas (GetDisplay ());

Image [] images =

LoadFrames ("/ images / bird",

Bird_frames);

INT W = C.Getwidth ();

INT H = C.GetHeight ();

Birds = new animatedimage [num_birds];

For (int i = 0; i

AnimatedImage B = New

AnimatedImage (C, Images);

BIRDS [I] = B;

B.Move (Genrandom (W), Genrandom (H));

C.Add (b);

Timer.schedule (B, Genrandom (1000),

Genrandom (400));

}

C.addcommand (exitcommand);

C.setCommandListener (this);

GetDisplay (). setcurrent (c);

}

Catch (IOException E) {

System.out.println ("COULD NOT

");

exitmidlet ();

}

}

// load the bird animation, Which is stored as a

// Series of png files in the midlet suite.

Private image [] loadframes (string name, int frames)

THROWS IOEXCEPTION {

Image [] images = new image [frames];

For (int i = 0; i

Images [i] = image.createImage (Name

i ".png");

}

Return images;

}

protected void pauseapp () {

}

protected void startapp ()

Throws MidletStateChangeException {

IF (Display == NULL) {

Display = display.getdisplay (this);

InitmIDlet ();

}

}

}

The seven-frame image set gives you an animation of a bird flapping its wings. The MIDlet places five birds at random locations with random refresh speeds. You can improve on this simple example in any number of ways, but it should be enough to get You going.

转载请注明原文地址:https://www.9cbs.com/read-93644.html

New Post(0)