科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道在移动设备上用J2ME实现动画

在移动设备上用J2ME实现动画

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

在移动设备上用J2ME实现动画

作者:blackpupil 来源:赛迪网技术社区 2007年10月31日

关键字: 动画 J2ME 移动设备

  • 评论
  • 分享微博
  • 分享邮件
使用MIDP(Mobile Information Device Profile)的开发人员经常会抱怨用些什么办法才可以在一个MIDlet上显示动画。 MIDP 1.0 没有直接提供对动画的支持(正在开发中的MIDP 2.0支持),但真要是自己去实现,其实也并非是一件很难的事。 {QD/X+55.  
  任何动画的最基本的前提,是要在足够快的时间内显示和更换一张张的图片,让人的眼睛看到动的画面效果。图片必须按照顺序画出来。从一张图片到下一张图片之间的变化越小,效果会越好。 9hn8TN`/  
  首先要做的,是使用你的图片处理软件(比如ps或者firework)创建一系列相同大小的图片来组成动画。每张图片代表动画一帧。需要制作一定数量的祯--越多的帧会让你的动画看上去越平滑。制作好的图片一定要保存成PNG(Portable Network Graphics)格式,MIDP唯一支持的图片格式;有两个办法让你刚做好的图片在MIDlet上变成动画。第一,把图片都放到一个web服务器上,让MIDlet下载他们,MIDP内置的HTTP支持。第二个办法更简单,把图片用MIDlet打包成jar文件。如果你使用的是J2ME开发工具,把PNG文件放入你的项目文件里面就可以了。 *_"9.@  
  动画的过程其实更像帐本记录:显示当前帧,然后适当地更换到下一帧。那么使用一个类来完成这个工作应该是很恰当的,那好,我们就先定义一个AnimatedImage类: j9*ok7A(^  
Copy code
.0mo}  
import java.util.*; -+^O#`$Hm  
import javax.microedition.lcdui.*; M-6dF>f/`C  
// 定义了一个动画,该动画其实只是一系列相同大小的图片 Bg=i.;.  
// 轮流显示,然后模拟出的动画 p:gTMJ:uB  
public class AnimatedImage extends TimerTask {; 'VkM`l(lj  
private Canvas canvas; $pm}z:cwE  
private Image[] images; 3Ct@p=Dc  
private int[][] clipList; V;NW8yA  
private int current; "0yK/  
private int x; ,snm4  
private int y; d`*P7s  
private int w; AJ jJ#2ZB  
private int h; jSX-z@kso  
// Construct an animation with no canvas. .'w"N1_.  
public AnimatedImage( Image[] images ){; 14Y`{8  
this( null, images, null ); pUgo2{&  
}; ||q/9_oSF  
// Construct an animation with a null clip list. {zJ#uh  
public AnimatedImage( Canvas canvas, Image[] \D{a8?aV  
images ){; this( canvas, images, null ); z* u\`.  
}; 97M0\MN8  
// Construct an animation. The canvas can be null, 6XwhaA.  
// but if not null then a repaint will be triggered ?1Z@nw-X9  
// on it each time the image changes due to a timer 1{y)iiaO>  
// event. If a clip list is specified, the image is fDI* 'k>D  
// drawn multiple times, each time with a different Q`6o`vT3  
// clip rectangle, to simulate transparent parts. DVQi5kL  
public AnimatedImage( Canvas canvas, Image[] images, MqIAll;  
int[][] clipList ){; Y+^ Boko=N  
this.canvas = canvas; v*%)GM  
this.images = images; F/%3(z41  
this.clipList = clipList; jm;heW1<  
if( images != null && clipList != null ){; s++b;K   
if( clipList.length < images.length ){; Q7peyuG  
throw new IllegalArgumentException(); iDv>;R^]Z=  
}; SsRf\o"  
}; VVq/LL90  
if( images != null && images.length > 0 ){; y Z*kgE  
w = images[0].getWidth(); bIz7A4/  
h = images[0].getHeight(); KHUip1/_  
}; v@v YQG/  
}; Q- xRiKVy  
// Move to the next frame, wrapping if necessary. m?jw+Ul'  
public void advance( boolean repaint ){; M8qz_1*9u  
if( ++current >= images.length ){; kzCf%a=J  
current = 0; L$0]]^=wf  
}; dmwrWmQ\  
if( repaint && canvas != null && canvas.isShown() CU:)D2N  
){; +<_?ZY+&N  
canvas.repaint( x, y, w, h ); p4ND: g`  
canvas.serviceRepaints(); 0u[9zz  
}; 44AhT[x   
}; S^]i}HeZ&  
// Draw the current image in the animation. If m>XUnv<fy  
// no clip list, just a simple copy, otherwise  s_\ZQ  
// set the clipping rectangle accordingly and cF\F?+wqR  
// draw the image multiple times. ]bQ=_W X  
public void draw( Graphics g ){; ;w&WCd?;  
if( w == 0 || h == 0 ) return; Y{ r^L  
int which = current; kW:nyvX  
if( clipList == null || clipList[which] == null DfoJm+oy  
){; sZ7rA_z n  
g.drawImage( images[which], x, y, Ogi-@=  
g.TOP | g.LEFT ); ,7;&O*vF ,  
}; else {; mVfae}3R>{  
int cx = g.getClipX(); c%^t6 pD  
int cy = g.getClipY(); >=F nv=  
int cw = g.getClipWidth(); c(m J0  
int ch = g.getClipHeight(); uXW!p--  
int[] list = clipList[which]; #@5~b p  
for( int i = 0; i + 3 <= list.length; i += I\iM pP  
4 ){; fZ)h ]!  
g.setClip( x + list[0], y + list[1], t$3j6h  
list[2], list[3] ); |PE]3I  
g.drawImage( images[which], x, y, 'd$\}+u[<  
g.TOP | g.LEFT ); hLp+zcsN  
}; j> gn4xA  
g.setClip( cx, cy, cw, ch ); u$t(\c@  
}; _/i#\-IK  
}; ftw3G#  
// Moves the animation´s top left corner. _zyk@79(  
public void move( int x, int y ){; E="gG.Al  
this.x = x;  /62)JE *  
this.y = y; 5jd!WAX  
}; mQe$h61%M  
// Invoked by the timer. Advances to the next frame #tM.PBe~L  
// and causes a repaint if a canvas is specified. Exd Vv  
public void run(){; l>EV~mDy  
if( w == 0 || h == 0 ) return; ~ -q)s  
advance( true ); aN['8ql,  
}; v;3crJ(>e  
}; ~*$pWQzw0  
SQ31z>r.o  
]1axC5 ~  
  你实例化一个AnimatedImage对象的时候你必须给AnimatedImage类的构造方法传一个Image对象数组,该数组代表动画的每一帧。 5vDG#s\^F  
  使用的所有图片必须具有相同的高度和宽度。用Image.createImage()方法从jar文件里面加载图片: ? b!K /$  
Copy code
*,0Z)JVM  
private Image[] loadFrames( String name, int frames ) G=O&{r  
throws IOException {; $kYztY0e  
Image[] images = new Image[frames]; {hJ. -pJ  
for( int i = 0; i < frames; ++i ){; ]j\c j$  
images = Image.createImage( name + i + ^N&sPh~  
".png" ); |H#6[/o`  
}; "I`?e|r  
return images; BW g_G]a|  
}; yy}s5W1He  
L<'N^Ome  
  你也可以传递一个Canvas对象(可选),和一个剪辑列表(clip list)。如果你指定了一个canvas和使用一个timer来自动更换到动画的下一帧,就如下面的例子代码中一样,canvas在动画向前滚动以后自动被重画(repaint)。不过这样的实现办法是可选的,你可以这样做,也可以让程序选择合适的时候重画canvas。 t9/XOSo@o  
  因为MIDP 1.0不支持透明的图片,AnimatedImage 类使用一个剪辑列表来模拟透明的效果,剪辑列表是图片被剪成的方块区域的系列。图片被画出来的时候分开几次,每次画一个剪辑列表里面的剪辑区域。剪辑列表在帧的基础上被定义好,所以你需要为图片的每一帧创建一个数组。数组的大小应该是4的倍数,因为每一个剪辑面积保持了四个数值:左坐标,顶坐标,宽度以及高度。坐标的原点是整个图片的左上角。需要注意的是使用了剪辑列表会使动画慢下来。如果图片更加复杂的话,你应该使用矢量图片。 f4fY91!V  
  AnimatedImage类扩展了java.util.TimerTask,允许你设定一个timer。这里有个例子说明如何使用timer做动画: `a.  [h  
Timer timer = new Timer();  B0r`9BI3  
AnimatedImage ai = ..... // get the image 'Vd^UN#zg  
timer.schedule( ai, 200, 200 ); Lu~ Ui[ 2  
  每隔大约200毫秒,timer调用AnimatedImage.run()方法一次,这个方法使得动画翻滚到下一个帧。 C5x4pB9  
现在我们需要的是让MIDlet来试试显示动画!我们定义一个简单的Canvas类的子类,好让我们把动画“粘贴上去”。 gTJhZ,dH  
Copy code
RB&Q)YK6  
import java.util.*; 36]pC7sI  
import javax.microedition.lcdui.*; lGk"V>GF  
// A canvas to which you can attach one or more <1|{i+c  
// animated images. When the canvas is painted, m_),}n#P  
// it cycles through the animated images and asks &~w=n  
// them to paint their current image. GU[ 3.q<py  
public class AnimatedCanvas extends Canvas {; Ux&b $EGe  
private Display display; k'dy";  
private Image offscreen; WoR$? %  
private Vector images = new Vector(); 7l=/"d0BL  
public AnimatedCanvas( Display display ){; /u o% 3  
this.display = display; ijQ#(YI   
// If the canvas is not double buffered by the ,qQy<)~,!  
// system, do it ourselves... = z2Bfea  
if( !isDoubleBuffered() ){; HAQ8 +  
offscreen = Image.createImage( getWidth(), yhb@"Kr  
getHeight() ); 67/#~j!g  
}; <lXitv^C  
}; 0?%u#$;N9S  
// Add an animated image to the list. i?:7[h-J  
public void add( AnimatedImage image ){; RnX PM0Y  
images.addElement( image ); KM<EjQ  
}; HW $X`  
// Paint the canvas by erasing the screen and then K^D9oos  
// painting each animated image in turn. Double \mF-&q&K  
// buffering is used to reduce flicker. y]x{x)M  
protected void paint( Graphics g ){; 6o|3nw3B  
Graphics saved = g; ;gv0i #  
if( offscreen != null ){; '>2~Q37#l  
g = offscreen.getGraphics(); = A7{<N  
}; d^u{3?`tj!  
g.setColor( 255, 255, 255 ); EXMzQ>EnZ  
g.fillRect( 0, 0, getWidth(), getHeight() );  (`ZKTQh  
int n = images.size(); $e4hQ!!  
for( int i = 0; i < n; ++i ){; UtU,g@cT4  
AnimatedImage img = (AnimatedImage) P3g +Q  
images.elementAt( i ); U$8Sb2zUP_  
img.draw( g ); N\)[Ti=  
}; "jD'7BM2M  
if( g != saved ){; ^p_<ED~DU  
saved.drawImage( offscreen, 0, 0, KM;]JE"   
Graphics.LEFT | Graphics.TOP ); ^;%any#ME  
}; %~zcxz]  
}; *R=}zguR)I  
}; cW 6|pK]  
`)R-iBQ=  
  AnimatedCanvas 类的代码相当简单,由一个动画导入方法和一个paint方法。canvas画布每次被画,背景都会被擦除,然后循环每个导入的AnimatedImage对象,直接画到自己身上来(自己扩展了canvas类)。 n]&@;kcT#O  
Copy code
Yei*2EP  
import java.io.*; `KK0K\D  
import java.util.*; -+LY)L>  
import javax.microedition.lcdui.*; e,1 > x  
import javax.microedition.midlet.*; k fS=x$&  
// MIDlet that displays some simple animations. AW=<E)  
// Displays a series of birds on the screen and mS>0cM"/  
// animates them at different (random) rates. GQNp5M3  
public class AnimationTest extends MIDlet G! 225\h  
implements CommandListener {; o_>Z\  
private static final int BIRD_FRAMES = 7; tpG=,3  
private static final int NUM_BIRDS = 5; ^}Fg8fd  
private Display display; -eYc~Y5  
private Timer timer = new Timer(); M2Qd Shz%  
private AnimatedImage[] birds; O894v}e  
private Random random = new Random(); @  .)+Hn  
public static final Command exitCommand = dMyatc\c  
new Command( "Exit", &pz9"[ E  
Command.EXIT, 1 ); q22K}W?  
public AnimationTest(){; H`o.c^c]  
}; >$x|A;~An  
public void commandAction( Command c, y%[p4LG-*/  
Displayable d ){; 5^r*y  
if( c == exitCommand ){; [\>4.i\^w  
exitMIDlet(); e!)FpT  
}; 7LxUME)}p  
}; L xzF8o7  
protected void destroyApp( boolean unconditional ) 1[r" 0  
throws MIDletStateChangeException {; Mmd}8'e,O+  
exitMIDlet(); VjL{;G37t  
}; LUoXhE%H  
public void exitMIDlet(){; zlwvp:b  
timer.cancel(); // turn it off... u{\(K_+y  
notifyDestroyed();  [z4f^^  
}; =THY/IP5U  
// Generate a non-negative random number... dZkEh`6Vf  
private int genRandom( int upper ){; Ky6ET%Y9  
return( Math.abs( random.nextInt() ) % upper ); ctu%O;=j  
}; ~Ib#`8Uy  
public Display getDisplay(){; return display; }; 2+[]ON$lS  
// Initialize things by creating the canvas and then Y Cx]d*kN  
// creating a series of birds that are moved to 1.kP[J  
// random locations on the canvas and attached to F9?:(hma'  
// a timer for scheduling.  cqX[nZ  
protected void initMIDlet(){; AN\c( X U  
try {; bv|`/|  
AnimatedCanvas c = new p[66+$rU  
AnimatedCanvas( getDisplay() ); OJE<9\K_L  
Image[] images = v+wiB`x  
loadFrames( "/images/bird", Wh+p\8k  
BIRD_FRAMES ); \7OEV0C  
int w = c.getWidth(); P}'cr  
int h = c.getHeight(); xm?`8{rcF)  
birds = new AnimatedImage[ NUM_BIRDS ]; {26703_fy  
for( int i = 0; i < NUM_BIRDS; ++i ){; `i'@Eg*  
AnimatedImage b = new  }3b Wf  
AnimatedImage( c, images ); 'QyOQ7;  
birds = b; vCvlBy~  
b.move( genRandom( w ), genRandom( h ) ); \V7g-dho  
c.add( b ); UG#&1i}Z  
timer.schedule( b, genRandom( 1000 ), mU_H0  
genRandom( 400 ) ); h;_B^'p#  
}; 8 lo9HyYc.  
c.addCommand( exitCommand ); c %f:.=  
c.setCommandListener( this ); -Y",f$  
getDisplay().setCurrent( c ); Ya.' Xx| ,  
}; <4J2Ly/4V  
catch( IOException e ){; ?YGr,RB  
System.out.println( "Could not Z5umZ#ilH  
load images" ); D5jP=a#  
exitMIDlet(); Z>|PH=JT!  
}; K'B kPT  
}; _":j-tl[L  
// Load the bird animation, which is stored as a 5<x5[z=  
// series of PNG files in the MIDlet suite. &kS10 6b<  
private Image[] loadFrames( String name, int frames ) < R`)+If  
throws IOException {; Ll+"^kI ^Q  
Image[] images = new Image[frames]; Z hMb-yf  
for( int i = 0; i < frames; ++i ){; .IC*5bzF+  
images = Image.createImage( name + :@@Ao~ej  
i + ".png" ); z|NJ^a"y  
}; W:ftr2piW  
return images; 1Pi KIp  
}; \}fNu"2Z  
protected void pauseApp(){; \T^B$9  
}; =*9Tat81  
protected void startApp() H^]yR1_**  
throws MIDletStateChangeException {; SOW7G T1[  
if( display == null ){; G2yvRm  
display = Display.getDisplay( this ); *&BT35Jlzp  
initMIDlet(); 1m:bwj"\  
}; eTP! $D  
}; @gB~V.CO+Q  
}; ;X!gq:c  
lT?.l: DUx  
  七帧图片的动画,你可以看到一个拍着翅膀的小鸟。MIDlet显示了5只小鸟,小鸟的位置和刷新速度是随机的。你可以用一些其他的办法来改进这个程序,但这个程序也应该足够能让你上手了。
查看本文来源
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章