J2ME小遊戲

J2ME小遊戲

J2ME 小遊戲即在消費類電子設備上運行的遊戲,例如在蜂窩電話、可視電話、數字機頂盒、汽車導航系統、個人數字助理(PDA)和移動手持設備(MID)上運行的小遊戲大多為J2ME小遊戲。J2ME是一種高度最佳化的Java運行環境,是Java的組成部分,它主要針對消費類電子設備的,在此基礎上設計出的遊戲統稱為J2ME 小遊戲。

簡介

J2ME小遊戲 J2ME小遊戲

一個J2ME的2D遊戲技術DEMO源碼

計畫了很久了,準備作為J2ME的Game APIs的例子貼出來,無奈一直不得空,直到最近才簡單地整理了一下,把它共享出來。

遊戲特色

嚴格地講,這個不能算作一個完整的遊戲,沒有自己的創意,只是簡單地模仿了一個Flash的小遊戲,當時是為了自己練習用的,Game Play也很簡單,但包含了J2ME的Game包中所有的東西,作為一個Demo來講,內容還是很充實的。

Gaming API分類

在介紹之前,先簡單地提一下Gaming API中的幾個類,包括Sprite,TiledLayer,LayerManager,Media.Player等。

Sprite

偶爾看到過有些人把它翻譯成精靈,我偷懶一下,就不翻譯了,這個類用來表達遊戲中的一個活動的角色,包括玩家控制的Player角色和非玩家控制的角色(NPC)。

TiledLayer

這個是用來表達背景的類,其實從繪圖的角度來看,Sprite和TiledLayer沒有本質差別,只是將要畫在螢幕上的一幅圖像而已,因此在Game包中它們都是Layer類的子類。並且都能夠從一幅圖像方便地構造。

LayerManager

這個是用來管理所有圖像對象的類,通過把Sprite和TiledLayer加入其中,J2ME設備就知道如何來繪製它們了。

GameCanvas

最後要提到的是畫布,這是所有可視對象最終要表演的舞台。其實跟以前的Canvas沒有本質的不同,同樣是提供了一個Graphics接口來供把一些內容畫上去而已,但增加了對玩家輸入的處理,能夠通過按鍵狀態來直接讀入玩家按鍵操作,相對更加簡便了。

還利用到了Media包中的Player和ToneControl來播放音樂,沒有音樂和聲音的遊戲是不可能出現的,呵呵。

操作指南

先簡單地介紹一下這個遊戲,玩家只能控制角色(一個端著網兜的小人)水平地移動,接住自然下落的小球就得分,積分到一定程度後,小球下落速度將加快,直到最高速為止;如果沒接到小球,也有相應的懲罰,最終遊戲會Game Over。

為了避免過於單調,玩家角色不是簡單地平移,而是利用了Sprite的簡單幀動畫來讓角色看上去有些動作。其實很方便的,只是在移動位置時更換一下圖像就行了,Sprite提供有幾個方法NextFrame(),PrevFrame()用來切換。

聲音部分就更簡單了,只是重複地播放一段預先寫進去的音樂,來自Sun的WTK中的一個例子。

不過既然提到了它,就還是先簡單地說一下吧,免得後面介紹其他部分時有些疑問。

J2ME中的聲音部分非常簡單,當然效果也不太好,所需的基本元素只有如下幾個,一個內容部分的Byte系列;一個是播放器Player;還有一個是控制部分的ToneControl。代碼示例如下:

tonePlayer = Manager.createPlayer(Manager.TONE_DEVICE_LOCATOR);

tonePlayer.setLoopCount(-1);

tonePlayer.realize();

ToneControl tc = (ToneControl)tonePlayer.getControl("javax.microedition.media.control.ToneControl");

tc.setSequence(mySequence);

當然還需要些初始化工作和異常處理,然後就可以通過tonePlayer.start()/close()方法來控制聲音的播放和停止了。

具體請參見源碼中CanvasGetBall.java中的createTonePlayer()方法。

鑼鼓響了半天,主角也該出場了。這個遊戲裡的主角只有一個接球小人,不過角色還有一個跟它演對手戲的NPC,就是那隻從天而降的小球了。這兩個類都是Sprite的子類,小球因為有些自己的動作,同時實現了Runnable接口,能自主活動。不過也很簡單,NPC嘛,一般來說都是相對弱智些,不然也沒法玩了,誰的反應速度跟得上機器啊,再說了,NPC知道的信息也要多些:)。

先來看看主角吧,BallPlayer類就是我們的主角,其實非常簡單,在所有的6個類中,除了記分用的Score外就數它最小了。提供一幅圖像把它實例化後,就只能通過左右移動來控制了,額外的幾個方法都是跟記分有關係的,先略過不提。

先來看看它的構造方法:

public BallPlayer(Image img, int fw, int fh) {

super(img, fw, fh);

this.step = fw / 2;

}

主要工作都由它的父類Sprite做了,給出一幅圖像,這個圖像是用PNG格式提供的,大家可能留意到不是一幅單一的圖像,而是有點象幀動畫中的幾個關鍵幀,不錯,的確如此,構造方法中的後兩個參數就是告訴Sprite如何分割這幅圖像的。這裡整個Player共有6個關鍵幀,比較粗糙,呵呵,自己動手截屏做的:)

Field step是用來控制主角的移動步伐的,為了快一點,取了它身寬的一半。

接下來我們看看如何移動它,就是通過這樣兩個方法來左移和右移。

public void left() {

prevFrame();

if( (getX() - step) >= -12 ) {

move( -1 * step, 0);

}

}

public void right () {

nextFrame();

if((getX() + step) < canvas.getWidth()) {

move(step, 0);

}

}

留意一下,這裡只管相對位移,主角的開始位置通過setPosition來設定,在運動過程中最好就不要直接設定位置了,增大計算量,要不就看起來動作不自然了。

接下來簡單說一下配角--球。球的構造跟主角類似,只是為了節省構造銷毀對象帶來的開銷,這個對象是一直存在的,也就是讓它掉下去了又自己起來,並根據記分來確定下落速度,簡單地用執行緒實現的,沒怎么仔細設計,大家看看代碼就清楚了。

再來看看CanvasGetBall這個類,它從GameCanvas繼承,並實現了CommandListener和Runnable兩個接口,是整個遊戲中最複雜的一個類了,主要工作有如下幾個部分,實例化主角,配角對象,還有背景對象,音樂等,並在適當的時候畫出這些對象,在頂部畫出些狀態信息,並根據玩家操作開始和暫停遊戲,並顯示相應畫面。並通過進行碰撞檢測來判定玩家是否接到了小球。

檢測方法

檢測方法如下:

private boolean notMiss( ) {

// return player.collidesWith(ball,false);

int ballCX = ball.getX() + ball.getWidth()/2;

int ballCY = ball.getY() + ball.getHeight()/2;

int playerCX = player.getX() + player.getWidth()/2;

int playerCY = player.getY() + player.getHeight()/2;

return ((Math.abs(playerCX - ballCX)< ball.getWidth()/2) &&

(Math.abs(ballCY - playerCY) < 5));

}

被注釋掉的一行是直接用Sprite的碰撞檢測,下面的部分是自己計算兩幅圖像有沒有重疊,效果差不多。其中collidesWith()的第二個參數是告訴內部方法是否要用像素級別的檢測,通常答案是千萬不要,這很慢的,而且沒有必要這么精確。

為了說明整個遊戲的控制邏輯,我們先來看看MIDletGetBall這個類,跟通常的MIDlet略有不同,因為我把主執行緒放在了CanvasGetBall中,MIDletGetBall只是簡單地控制主執行緒就行了。

public void startMainThread() {

Display.getDisplay(this).setCurrent(displayable);

if(mainThread != null) {

mainThread = null;

Runtime.getRuntime().gc();

}

mainThread = new Thread(displayable);

mainThread.start();

}

其中第一行就是設定當前顯示頁面;也就是顯示CanvasGetBall。

回到CanvasGetBall,整個遊戲分幾個階段,相應有不同的畫面和命令接口,詳細說明如下:

1. 等待開始,對應在方法ready():

public void ready() {

cover.setTitle(TIPS[2]);

cover.addCommand(playCommand);

Display.getDisplay(MIDletGetBall.instance).setCurrent(cover);

}

為了繪製方便,這裡單獨用了個GameCanvas來繪製提示信息和回響命令,並根據玩家操作在CanvasCover和CanvasGetBall兩個畫面之間來回切換。

2. 遊戲畫面,包括啟動和結束兩個方法:

public void start() {

if(!playing) {

strTip = TIPS[0];

playing = true;

MIDletGetBall.instance.startMainThread();

removeCommand(playCommand);

removeCommand(resumeCommand);

addCommand(pauseCommand);

ball.start();

try {

if(tonePlayer != null) {

tonePlayer.start();

}

}

catch (MediaException ex) {

tonePlayer.close();

tonePlayer = null;

}

}

}

public void stop () {

if(playing) {

ball.stop();

strTip = TIPS[1];

try {

Thread.sleep(300);

}

catch (InterruptedException ex) {

}

playing = false;

removeCommand(pauseCommand);

addCommand(resumeCommand);

try {

tonePlayer.stop();

}

catch (MediaException ex1) {

tonePlayer.close();

tonePlayer = null;

}

}

}

並對應設定相應的命令來讓玩家能夠繼續下去,構成一個簡單的封閉控制環路。

3.遊戲結束,對應方法gameover()

public void gameover() {

this.stop();

cover.setTitle(TIPS[3]);

cover.removeCommand(playCommand);

cover.addCommand(restartCommand);

Display.getDisplay(MIDletGetBall.instance).setCurrent(cover);

}

說到這裡,基本上也就把它講完了,具體內容請詳細研究源碼,其實沒必要看太多書,深入地研究一個問題並根據自己的理解來改進或者是修正它,實踐才是最好的老師,希望大家能夠有所收穫。

存在的問題

總結一下,這個遊戲存在的問題有如下幾個:

1. 沒有好的Game Play,畫面很差;

2. 可玩性不強,控制比較單調;

3. 遊戲聲音過於單調;

4. 運行速度有些慢。

但作為一個技術Demo,它涵蓋了Game包中的所有內容,並提供了一個利用執行緒方式實現簡單遊戲的方法,很簡單,但不適合真實的遊戲,比較費時。

背景處理很差,可以通過一個Map來分割組合處理背景小片,能讓遊戲場景變得生動些,可以實現類似於捲軸遊戲的效果,自己試試吧!

附:原始碼和工程,在JBuilderX下編譯,同時需要WTK2.0或以上版本。好久沒有用Jbuilder了,買不起正版:),現在主要開發工具是Eclipse和EclipseME,感覺非常爽,免費的也有好貨。

相關詞條

相關搜尋

熱門詞條

聯絡我們