服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

nokia ui学习范例fishtank研究

    由于midp1.0中提供的api比较有限,因此nokia实现了自己的类库来提供补充。其中包括声音的支持、屏幕的背景光和机器震动、图像的翻转、alpha通道以及对像素的操作支持。学习nokia ui的使用的最好例子莫过于nokia官方提供的fishtank了。本文讲主要介绍一下这个范例,其中的一些思路和技巧是值得我们学习的。

nokia ui学习范例fishtank研究(图一)fishtank的界面比较简单,只有一个屏幕。池塘里的鱼儿不停的游动,水底的水草也不停的漂浮。这个界面是分层设计的,因此引入了一个变量z,这样就和水平参数x和垂直参数y构成了三维的空间。其中水草处于中间层。鱼的游动是无规律的,其中的算法我们可以参考,当鱼触及到边缘的时候,它会反向游动。通过nokia ui中提供的水平翻转可以实现。 dg.drawimage(img, x, y, (graphics.left | graphics.top),directgraphics.flip_horizontal);水草的游动也是随机的

 

    下面我们看看整个应用的结构
nokia ui学习范例fishtank研究(图二)

点击查看大图

 

 

 

 

 

 

 

程序总共有四个类组成,其中我们主要关注的是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的代码设计比较合理,代码思路清晰。比较容易维护和扩展。另外程序中随机性的算法也可以用于实际工作中。您可以从这里下载全部代码点击浏览该文件

扫描关注微信公众号