文章导航PC6首页软件下载单机游戏安卓资源苹果资源

pc软件新闻网络操作系统办公工具编程服务器软件评测

安卓新闻资讯应用教程刷机教程安卓游戏攻略tv资讯深度阅读综合安卓评测

苹果ios资讯苹果手机越狱备份教程美化教程ios软件教程mac教程

单机游戏角色扮演即时战略动作射击棋牌游戏体育竞技模拟经营其它游戏游戏工具

网游cf活动dnf活动lol周免英雄lol礼包

手游最新动态手游评测手游活动新游预告手游问答

您的位置:首页精文荟萃软件资讯 → 利用J2ME在移动设备上实现动画的解决方案

利用J2ME在移动设备上实现动画的解决方案

时间:2004/10/8 13:18:00来源:本站整理作者:蓝点我要评论(0)

  使用MIDP(Mobile Information Device Profile)的开发人员经常会抱怨用些什么办法才可以在一个MIDlet上显示动画。MIDP 1.0 没有直接提供对动画的支持(MIDP 2.0支持),但真要是自己去实现,其实也并非是一件很难的事。


  任何动画的最基本的前提,是要在足够快的时间内显示和更换一张张的图片,让人的眼睛看到动的画面效果。图片必须按照顺序画出来。从一张图片到下一张图片之间的变化越小,效果会越好。


  首先要做的,是使用你的图片处理软件(比如ps或者firework)创建一系列相同大小的图片来组成动画。每张图片代表动画一帧。你需要制作一定数量的祯--越多的帧会让你的动画看上去越平滑。制作好的图片一定要保存成PNG(Portable Network Graphics)格式,MIDP唯一支持的图片格式。


  有两个办法让你刚做好的图片在MIDlet上变成动画。第一,把图片都放到一个web服务器上,让MIDlet下载他们,MIDP内置的HTTP支持。第二个办法更简单,把图片用MIDlet打包成jar文件。如果你使用的是J2ME开发工具,把PNG文件放你的项目文件里面就可以了。


  动画的过程其实更像帐本记录:显示当前帧,然后适当地更换到下一帧。那么使用一个类来完成这个工作应该是很恰当的,那好,我们就先定义一个AnimatedImage类:


import java.util.*;
import javax.microedition.lcdui.*;
// 定义了一个动画,该动画其实只是一系列相同大小的图片
// 轮流显示,然后模拟出的动画
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 );
 };
}; 


  你实例化一个AnimatedImage对象的时候你必须给AnimatedImage类的构造方法传一个Image对象数组,该数组代表动画的每一帧。使用的所有图片必须具有相同的高度和宽度。


  用Image.createImage()方法从jar文件里面加载图片:


private Image[] loadFrames( String name, int frames )
throws IOException {;
 Image[] images = new Image[frames];
 for( int i = 0; i < frames; ++i ){;
  images = Image.createImage( name + i +".png" );
 };
 return images;
}; 


  你也可以传递一个Canvas对象(可选),和一个剪辑列表(clip list)。如果你指定了一个canvas和使用一个timer来自动更换到动画的下一帧,就如下面的例子代码中一样,canvas在动画向前滚动以后自动被重画(repaint)。不过这样的实现办法是可选的,你可以这样做,也可以让程序选择合适的时候重画canvas。


  因为MIDP 1.0不支持透明的图片,AnimatedImage 类使用一个剪辑列表来模拟透明的效果,剪辑列表是图片被剪成的方块区域的系列。图片被画出来的时候分开几次,每次画一个剪辑列表里面的剪辑区域。剪辑列表在帧的基础上被定义好,所以你需要为图片的每一帧创建一个数组。数组的大小应该是4的倍数,因为每一个剪辑面积保持了四个数值:左坐标,顶坐标,宽度以及高度。坐标的原点是整个图片的左上角。需要注意的是使用了剪辑列表会使动画慢下来。如果图片更加复杂的话,你应该使用矢量图片。


  AnimatedImage类扩展了java.util.TimerTask,允许你设定一个timer。这里有个例子说明如何使用timer做动画:


Timer timer = new Timer();
AnimatedImage ai = ..... // get the image
timer.schedule( ai, 200, 200 ); 


  每隔大约200毫秒,timer调用AnimatedImage.run()方法一次,这个方法使得动画翻滚到下一个帧。现在我们需要的是让MIDlet来试试显示动画!我们定义一个简单的Canvas类的子类,好让我们把动画“粘贴上去”。


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 );
  };
 };
}; 


  AnimatedCanvas 类的代码相当简单,由一个动画导入方法和一个paint方法。canvas画布每次被画,背景都会被擦除然后循环每个导入的AnimatedImage对象,直接画到自己身上来(自己扩展了canvas类)。


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 = 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 = Image.createImage( name + i + ".png" );
  };


  return images;
 };


 protected void pauseApp(){; };


 protected void startApp()
 throws MIDletStateChangeException {;
  if( display == null ){;
   display = Display.getDisplay( this );
   initMIDlet();
  };
 };
}; 


  七帧图片的动画,你可以看到一个拍着翅膀的小鸟。MIDlet显示了5只小鸟,小鸟的位置和刷新速度是随机的。你可以用一些其他的办法来改进这个程序,但这个程序也应该足够能让你上手了。


相关阅读 Windows错误代码大全 Windows错误代码查询激活windows有什么用Mac QQ和Windows QQ聊天记录怎么合并 Mac QQ和Windows QQ聊天记录Windows 10自动更新怎么关闭 如何关闭Windows 10自动更新windows 10 rs4快速预览版17017下载错误问题Win10秋季创意者更新16291更新了什么 win10 16291更新内容windows10秋季创意者更新时间 windows10秋季创意者更新内容kb3150513补丁更新了什么 Windows 10补丁kb3150513是什么

文章评论
发表评论

热门文章 360快剪辑怎么使用 36金山词霸如何屏幕取词百度收购PPS已敲定!3

最新文章 微信3.6.0测试版更新了微信支付漏洞会造成哪 360快剪辑怎么使用 360快剪辑软件使用方法介酷骑单车是什么 酷骑单车有什么用Apple pay与支付宝有什么区别 Apple pay与贝贝特卖是正品吗 贝贝特卖网可靠吗

人气排行 xp系统停止服务怎么办?xp系统升级win7系统方电脑闹钟怎么设置 win7电脑闹钟怎么设置office2013安装教程图解:手把手教你安装与qq影音闪退怎么办 QQ影音闪退解决方法VeryCD镜像网站逐个数,电驴资料库全集同步推是什么?同步推使用方法介绍QQ2012什么时候出 最新版下载EDiary——一款好用的电子日记本