fishtank的界面比较简单,只有一个屏幕。池塘里的鱼儿不停的游动,水底的水草也不停的漂浮。这个界面是分层设计的,因此引入了一个变量z,这样就和水平参数x和垂直参数y构成了三维的空间。其中水草处于中间层。鱼的游动是无规律的,其中的算法我们可以参考,当鱼触及到边缘的时候,它会反向游动。通过nokia ui中提供的水平翻转可以实现。 dg.drawimage(img, x, y, (graphics.left | graphics.top),directgraphics.flip_horizontal);水草的游动也是随机的
下面我们看看整个应用的结构
程序总共有四个类组成,其中我们主要关注的是fishtankcanvas、fish和weeds。其中fish和weeds比较相似,他们代表了两个对象鱼儿和水草。而fishtankcanvas是fullcanvas的子类并且实现了runnable接口,它是一个独立的线程。每隔一段时间他会更新一下fish和weeds的状态,然后重新绘制屏幕。run()方法中的代码如下
public void run()
{
thread currentthread = thread.currentthread();
try
{
// this ends when animationthread is set to null, or when
// it is subsequently set to a new thread; either way, the
// current thread should terminate
while (currentthread == animationthread)
{
long starttime = system.currenttimemillis();
// only animate when the canvas is visible.
if (isshown())
{
tick();
// repaint everything above the sand, the fish
// never swim at h > waterheight.
repaint(0, 0, waterwidth, waterheight);
servicerepaints();
}
long timetaken = system.currenttimemillis() - starttime;
if (timetaken < millis_per_tick)
{
synchronized (this)
{
wait(millis_per_tick - timetaken);
}
} else
{
currentthread.yield();
}
}
} catch (interruptedexception e)
{
}
}
由于在屏幕的下方有一部分是泥土,因此在这里调用了repaint(0,0,waterwidth,waterlength)。其实fishtankcanvas同时也是一个容器类,它是fish和weeds的容器。他去更新fish和weeds的状态然后调用各自的draw()方法来重新绘制。下面我们看看fishtankcanvas是如何绘制的
private synchronized void drawfishtank(graphics g)
{
// draw the water
g.setcolor(0, 255, 255);
g.fillrect(0, 0, waterwidth, waterheight);
// draw the sand
g.setcolor(255, 128, 64);
g.fillrect(0, waterheight, waterwidth, getheight());
// draw the weeds and fishes
for (int plane = 0; plane < num_planes; plane++)
{
if (plane == weeds_plane)
{
weeds.draw(g);
}
for (int i = 0; i < fishes.size(); i++)
{
fish fish = (fish) (fishes.elementat(i));
if (fish.getz() == plane)
{
fish.draw(g);
}
}
}
}
接下来我们研究一下fish和weeds的代码,它们就是有很多图片构成的。实现的结果和midp2.0中的sprite差不多。fish和weeds的图片都是有类型之分的,每个类型又有几个桢。这样才可以构造出不同的对象,并且相同的对象在不同的时刻也有不同的状态。
private static final int type_num = 3;
private static final int frame_num = 2;
private static final image[][] fishimage;
fish和weeds都是采用了静态初始化块的方式来初始化相应的二维数组。例如
static
{
fishimage = new image[type_num][frame_num];
int i = 0;
int k = 0;
try
{
for (i = 0; i < type_num; i++)
{
for (k = 0; k < frame_num; k++)
{
fishimage[i][k] = image.createimage("/fish" + i + k
+ ".png");
}
}
} catch (java.io.ioexception e)
{
fishimage[i][k] = null;
}
// this midlet implicitly assumes that all the images
// are the same width and height.
fishwidth = fishimage[0][0].getwidth();
fishheight = fishimage[0][0].getheight();
}
为了让鱼儿或者水草具有更好的随机性,代码是通过如下的算法来控制他们的方向的,下面以方向x为例说明
// mostly continue as we are, but sometimes randomly change
if ((tickssincelastchangex > 20) && (rand(20) == 0))
{
vx = rand(2) * 2 - 1; // -1 or 1
tickssincelastchangex = 0;
}
// if moving would take us off the left or right of the water,
// reverse
if (((vx < 0) && (x + vx < 0))
|| ((vx > 0) && (x + fishwidth + vx > fishtankcanvas.waterwidth)))
{
vx = -vx;
tickssincelastchangex = 0;
}
当鱼接触到水的边缘的时候,它的速度方向会改变。在此前的代码是为了增加他的随机性。fish的重新绘制也比较简单,这里用到了nokia ui中的水平翻转的扩展功能
public void draw(graphics g)
{
directgraphics dg = directutils.getdirectgraphics(g);
image img = fishimage[type][frame];
if (img != null)
{
if (vx < 0)
{
dg.drawimage(img, x, y, (graphics.left | graphics.top),
directgraphics.flip_horizontal);
} else
{
dg.drawimage(img, x, y, (graphics.left | graphics.top), 0);
}
}
frame = (frame + rand(2)) % frame_num;
}
我们可以看到每次绘画结束后都会把frame的编号随机设置一下,这样可以得到鱼儿本身运动的效果。
midlet的代码比较简单,直接给出
package example.fishtank;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class fishtankmidlet extends midlet
{
private final fishtankcanvas canvas;
public fishtankmidlet()
{
canvas = new fishtankcanvas(this);
}
public void startapp()
{
display.getdisplay(this).setcurrent(canvas);
canvas.start();
}
public void pauseapp()
{
canvas.stop();
}
public void destroyapp(boolean unconditional)
{
canvas.stop();
}
/*
* on the exit command, cleanup and notify that the midlet has been
* destroyed.
*/
void exitrequested()
{
destroyapp(false);
notifydestroyed();
}
}
总结:我们在本文中可以学到如何使用nokia ui中提供给我们的扩展功能,比如水平翻转、全屏显示等。更重要的是,fishtank的代码设计比较合理,代码思路清晰。比较容易维护和扩展。另外程序中随机性的算法也可以用于实际工作中。您可以从这里下载全部代码点击浏览该文件
闽公网安备 35060202000074号