原文見: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(0, 0, 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, 圖1是運行結果。

圖1. 構建一個游戲:使用GameCanvas類
使用設備的方向鍵可以左右移動屏幕中的小圖像,這是通過從checkUserInput()里取得按鍵狀態,然后調用calculateCoupleX(),通過將按鍵狀態與GameCanvas里預定義的按鍵值進行與操作(&),得到用戶當前按的鍵,然后將實例變量更新,最終反映到設備屏幕上。
圖像是在updateGameScreen()方法里被繪制到屏幕上的。這個方法使用傳入的Graphics對象進行繪制,每一個GameCanvas只有一個Graphics對象。方法首先擦除上次繪制的圖像,然后基于當前的coupleX值(還有一直不變的coupleY值)繪制couple.gif圖像,最后將緩沖區的數據輸出到屏幕。
run()方法里的循環體遵循我們剛開始提出的游戲結構。循環每30毫秒檢查一次用戶輸入并刷新屏幕。你可以試著將這個值改變一下,這會改變刷新的頻率。
最后,注意MyGameCanvas的構造器里調用了父類GameCanvas的構造方法,傳入的參數為true,這表示從Canvas類繼承的按鍵事件機制被抑制了,因為我們的代碼不需要這些通知機制。我們的游戲狀態用GameCanvas里自帶的按鍵信息(由getKeyStates()方法取得)來處理已經足夠了。通過抑制“keyPressed”、“keyReleased”和“keyRepeated”等通知機制,可以提高游戲的性能。
版權所有 羅明