WEB开发网
开发学院软件开发Java 基于MIDP1.0实现动画效果 阅读

基于MIDP1.0实现动画效果

 2007-12-23 12:32:18 来源:WEB开发网   
核心提示: 在SUN的技术文章里面有一篇文章讲述了如何基于MIDP1.0实现动画,个人觉得很不错,基于MIDP1.0实现动画效果,在MIDP1.0中并为直接对动画提供支持,如果我们明白动画的原理,而且我们也不适宜把动画图片作的过大,这样会增大jar文件的大小,熟悉Timer和TimerTask的话实现动画并非很困难的事情,

   在SUN的技术文章里面有一篇文章讲述了如何基于MIDP1.0实现动画,个人觉得很不错。在MIDP1.0中并为直接对动画提供支持,如果我们明白动画的原理,熟悉Timer和TimerTask的话实现动画并非很困难的事情。

   动画实际上就是一系列连续的帧,当他们变换的足够快的时候,我们人的眼睛就会觉得他是运动的。所以如果我们能够周期性的切换画面,从第一帧到第二帧到第三帧 ......那么我们就可以制作出动画的效果了。Timer和TimerTask正好可以很好的帮我们完成这一功能,如果你还不熟悉这两个类可以参考使用java中的Timer和TimerTask。我们首先扩展TimerTask实现AnimatedImage类,它的功能就是在特定位置画图

import java.util.*;
import javax.microedition.lcdui.*;

// Defines an animated image, which is just a set
// of images of equal size which are drawn in turn
// to simulate movement.

public class AnimatedImage extends TimerTask
{
   PRivate Canvas canvas;
   private Image[] images;
   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[] images)
   {
     this(null, images, null);
   }

   // Construct an animation with a null clip list.

   public AnimatedImage(Canvas canvas, Image[] images)
   {
     this(canvas, images, null);
   }

   // Construct an animation. The canvas can be null, but
   // if not null then a repaint will be triggered on it
   // each time the image changes due to a timer event.
   // If a clip list is specified, the image is drawn
   // multiple times, each time with a different clip
   // rectangle, to simulate transparent parts.

   public AnimatedImage(Canvas canvas, Image[] images, int[][] clipList)
   {
     this.canvas = canvas;
     this.images = images;
     this.clipList = clipList;

   if (images != null && clipList != null)
     {
       if (clipList.length < images.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 timer. Advances to the next frame
   // and causes a repaint if a canvas is specified.

   public void run()
   {
     if (w == 0 h == 0)
       return;

   advance(true);
   }
}

我们需要预先在jar文件里面存储几个大小一样,形态有序的图片,在MIDlet启动的时候把它装载在一个Image数组,并把它作为参数传递给AnimatedImage。
private Image[] loadFrames( String name, int frames )
                  throws IOException {
   Image[] images = new Image[frames];
   for( int i = 0; i < frames; ++i ){
 images[i] = Image.createImage( name + i +
       ".png" );
   }

   return images;
}

Image[] frames = loadFrames( "/images/bird", 7 );
AnimatedImage ai = new AnimatedImage( frames );
ai.move( 20, 20 ); // set top-left to 20,20

下面是两个测试效果的AnimatedCanvas和AnimationTest类的源代码,在这里你可以得到全部的源文件和图片资源。仔细读读这几个类是很有好处的。有一点值得一提的是,在绘制图片的时候应该判断设备是否支持双缓冲,如果不支持要使用双缓冲技术避免画面闪烁。而且我们也不适宜把动画图片作的过大,这样会增大jar文件的大小,同时会给设备造成很大的负担。

   protected void paint(Graphics g)
   {
     Graphics saved = g;

   if (offscreen != null)
     {
       g = offscreen.getGraphics();
     }

   g.setColor(255, 255, 255);
     g.fillRect(0, 0, getWidth(), getHeight());

   int n = images.size();
     for (int i = 0; i < n; ++i)
     {
       AnimatedImage img = (AnimatedImage) images.elementAt(i);
       img.draw(g);
     }


     if (g != saved)
     {
       saved.drawImage(offscreen, 0, 0, Graphics.LEFT Graphics.TOP);
     }
   }

import java.io.*;
import java.util.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;

// MIDlet that displays some simple animations.
// 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 static final int NUM_BIRDS = 5;

   private Display display;
   private Timer timer = new Timer();
   private AnimatedImage[] birds;
   private Random random = new Random();

   public static final 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 < NUM_BIRDS; ++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 load images");
       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 < frames; ++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();
     }
   }
}


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 Image 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 ourselves...

   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 used to reduce flicker.

   protected void paint(Graphics g)
   {
     Graphics saved = g;

   if (offscreen != null)
     {
       g = offscreen.getGraphics();
     }

   g.setColor(255, 255, 255);
     g.fillRect(0, 0, getWidth(), getHeight());

   int n = images.size();
     for (int i = 0; i < n; ++i)
     {
       AnimatedImage img = (AnimatedImage) images.elementAt(i);
       img.draw(g);
     }


     if (g != saved)
     {
       saved.drawImage(offscreen, 0, 0, Graphics.LEFT Graphics.TOP);
     }
   }
}

(出处:http://www.cncms.com)


Tags:基于 MIDP 实现

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接