罗明的博客
... ...
讨论Eclipse, Java, Linux, Google产品
              

原文见:http://today.java.net/pub/a/today/2005/07/07/j2me3.html?page=2

构建一个J2ME游戏:从GameCanvas类开始

GameCanvas类继承自Canvas,提供了一个屏幕后端的缓冲区,所有的绘制操作都先在这个缓冲区里进行。当所有绘制操作完成后,我们调用flushGraphics()方法将缓冲区内容输出到屏幕。这种双缓冲机制可以使图像的移动更加平滑,避免图像的闪烁。缓冲区大小等于屏幕的大小,而且每一个GameCanvas实例有且仅有一个缓冲区。

GameCanvas类提供一种存储按键状态的机制,我们可以通过它方便的了解用户与游戏的交互。这种机制可以跟踪用户按特殊键的次数,调用getKeyStates()方法返回所有游戏键按键状态的二进制表示,1代表上次调用方法后按过该键,0表示上次调用后还没有按过该键。我们可以跟踪的游戏状态有(这里的键都是在Canvas类里定义的):DOWN_PRESSED, UP_PRESSED, RIGHT_PRESSED, LEFT_PRESSED, FIRE_PRESSED, GAME_A_PRESSED, GAME_B_PRESSED, GAME_C_PRESSED和GAME_D_PRESSED。

首先扩展GameCanvas类,定制一个游戏画布,代码见清单1。清单2是运行例子的MIDlet。

package com.j2me.part3;

import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.game.GameCanvas;

import java.io.IOException;

public class MyGameCanvas
    
extends GameCanvas
    
implements Runnable
{
    
public MyGameCanvas()
    
{
        
super(true);
    }

    
    
public void start()
    
{
        
try
        
{
            
//导入couple图片,坐标定位在屏幕中央
            coupleImg = Image.createImage("/couple.gif");
            coupleX 
= CENTER_X;
            coupleY 
= CENTER_Y;
        }

        
catch(IOException ioex)
        
{
            System.err.println(ioex);
        }

        
        Thread runner 
= new Thread(this);
        runner.start();
    }

    
    
public void run()
    
{
        
//获取画布的graphics对象
        Graphics g = getGraphics();
        
        
while(true//无穷循环
        {
            
//基于上一个代码清单列出的结构
            
            
//首先检查游戏状态
            verifyGameState();
            
            
//检查用户输入
            checkUserInput();
            
            
//更新屏幕
            updateGameScreen(getGraphics());
            
            
//休息一下,控制刷新频率
            try
            
{
                Thread.currentThread().sleep(
30);
            }

            
catch(Exception e)
            
{}
        }

    }

    
    
private void verifyGameState()
    
{
        
//现在先不做任何操作
    }

    
    
private void checkUserInput()
    
{
        
//获取按键信息
        int keyState = getKeyStates();
        
        
//计算x轴位置
        calculateCoupleX(keyState);
    }

    
    
private void updateGameScreen(Graphics g)
    
{
        
//清空屏幕背景
        g.setColor(0xffffff);
        g.fillRect(
00, getWidth(), getHeight());
        
        
//将couple图片绘制到当前坐标位置
        g.drawImage(
            coupleImg, coupleX, coupleY, Graphics.HCENTER 
|
            Graphics.BOTTOM);
        
        flushGraphics();
    }

    
    
private void calculateCoupleX(int keyState)
    
{
        
//判断移动方向
        if((keyState & LEFT_PRESSED) != 0)
        
{
            coupleX 
-= dx;
        }

        
else if((keyState & RIGHT_PRESSED) != 0)
        
{
            coupleX 
+= dx;
        }

    }

    
    
private Image coupleImg;
    
private int coupleX;
    
private int coupleY;
    
private int dx = 1//移动量
    
    
//屏幕中心
    public final int CENTER_X = getWidth() / 2;
    
public final int CENTER_Y = getHeight() / 2;
}

清单 1. MyGameCanvas:游戏画布的第一个版本

清单 2 是使用这个游戏画布的MIDlet:

package com.j2me.part3;

import javax.microedition.lcdui.Display;
import javax.microedition.midlet.MIDlet;

public class GameMIDlet extends MIDlet
{
    MyGameCanvas gCanvas;
    
    
public GameMIDlet()
    
{
        gCanvas 
= new MyGameCanvas();
    }

    
    
public void startApp()
    
{
        Display d 
= Display.getDisplay(this);
        gCanvas.start();
        
        d.setCurrent(gCanvas);
    }

    
    
public void pauseApp()
    
{}
    
    
public void destroyApp(boolean unconditional)
    
{}
}

清单 2. 运行游戏示例的MIDlet类

使用Wireless工具建立一个工程,导入这两个类,然后生成并运行工程。确保你的工程目录res中有这个图片文件couple.gif,并保证名称为couple.gif, 图1是运行结果。

j2me3_figure1.gif
图1. 构建一个游戏:使用GameCanvas类

使用设备的方向键可以左右移动屏幕中的小图像,这是通过从checkUserInput()里取得按键状态,然后调用calculateCoupleX(),通过将按键状态与GameCanvas里预定义的按键值进行与操作(&),得到用户当前按的键,然后将实例变量更新,最终反映到设备屏幕上。

图像是在updateGameScreen()方法里被绘制到屏幕上的。这个方法使用传入的Graphics对象进行绘制,每一个GameCanvas只有一个Graphics对象。方法首先擦除上次绘制的图像,然后基于当前的coupleX值(还有一直不变的coupleY值)绘制couple.gif图像,最后将缓冲区的数据输出到屏幕。

run()方法里的循环体遵循我们刚开始提出的游戏结构。循环每30毫秒检查一次用户输入并刷新屏幕。你可以试着将这个值改变一下,这会改变刷新的频率。

最后,注意MyGameCanvas的构造器里调用了父类GameCanvas的构造方法,传入的参数为true,这表示从Canvas类继承的按键事件机制被抑制了,因为我们的代码不需要这些通知机制。我们的游戏状态用GameCanvas里自带的按键信息(由getKeyStates()方法取得)来处理已经足够了。通过抑制“keyPressed”、“keyReleased”和“keyRepeated”等通知机制,可以提高游戏的性能。



版权所有 罗明
posted on 2005-12-08 18:01 罗明 阅读(2435) 评论(3)  编辑  收藏 所属分类: JavaJ2ME
Comments
  • # 好好学习
    ken
    Posted @ 2005-12-09 10:55
    package com.j2me.part3;

    import javax.microedition.lcdui.Display;
    import javax.microedition.midlet.MIDlet;

    这个地方看不懂,清单1和清单2怎么两个相同的包名在,不是引用么  回复  更多评论   
  • # re: J2ME Tutorial, Part 3: 探究MIDP 2.0的游戏API(二)
    Andy luo
    Posted @ 2005-12-09 11:28
    这两个类是放在一起的(一个包中),只不过清单2是主类,包含了一个清单1的实例。项目运行时执行清单2的MIDlet,然后清单1执行相应的绘制操作。  回复  更多评论   
  • # Meta-Tegi
    Meta-Tegi
    Posted @ 2009-05-18 03:37
    Hello everyone. Eat a third and drink a third and leave the remaining third of your stomach empty. Then, when you get angry, there will be sufficient room for your rage.
    I am from Pakistan and too bad know English, tell me right I wrote the following sentence: "Seo best practices innovations from chicago based seo consultant and resolution media associate director of search engine optimization, bryson meunier.In addition to pure seo services and web marketing, I have a lot of experience."

    Best regards :), Patricia.  回复  更多评论   

只有注册用户登录后才能发表评论。


网站导航: