J2ME-MIDP1.0小游戲基礎(chǔ)-5子棋1.0
發(fā)表時間:2024-06-11 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]作者:yinowl2005年1月介紹這是我學(xué)習(xí)j2me入門后的第一個作品,當(dāng)然這也是一個極其簡單的作品(沒有電腦AI,只能是兩個人對戰(zhàn)),現(xiàn)在我把當(dāng)時的設(shè)計思路寫成這篇文檔,希望對想入門j2me的朋友在j2me的流程,按鍵響應(yīng),繪圖等方面有所幫助,同時也希望大家指出錯誤和改進(jìn)程序。注意代碼列出解釋...
作者:yinowl
2005年1月
介紹
這是我學(xué)習(xí)j2me入門后的第一個作品,當(dāng)然這也是一個極其簡單的作品(沒有電腦AI,只能是兩個人對戰(zhàn)),現(xiàn)在我把當(dāng)時的設(shè)計思路寫成這篇文檔,希望對想入門j2me的朋友在j2me的流程,按鍵響應(yīng),繪圖等方面有所幫助,同時也希望大家指出錯誤和改進(jìn)程序。
注意
代碼列出解釋的形式仿照《J2ME Game Programming》一書,按照程序功能思路給出相關(guān)代碼,一個文件的代碼會根據(jù)功能在不同的小節(jié)給出,文章結(jié)束了,代碼也就完整了。這不同于通常書中的代碼以文件為單位一次全部給出,我認(rèn)為這樣更有助于讓大家了解一個程序從設(shè)計到最后完成的思路。
設(shè)計
數(shù)據(jù)結(jié)構(gòu):由于五子棋是一個二維棋類游戲,所有首先想到的是定義一個Chesses類來表示棋子,Chesses有一個boolean型的變量isPlayer1來區(qū)分該棋子是哪玩家下的,然后用一個Chess類型的二維數(shù)組來包含棋盤上的所有棋子?紤]到移動設(shè)備的資源有限,盡可能減少系統(tǒng)資源占用,我考慮不在數(shù)組建立后直接生成數(shù)組的每一個對象,而是把每一個棋子對象(Chesses)放在游戲的進(jìn)行中生成,也就是說在游戲進(jìn)行時,玩家每下一步棋,在數(shù)組相應(yīng)位置生成該棋子的對象,這樣可以避免還沒有下的棋子在一開始就占用了系統(tǒng)內(nèi)存
流程:游戲按照棋子的二維數(shù)組進(jìn)行繪制棋子,玩家下棋后,程序修改數(shù)組相應(yīng)位置,設(shè)置isPlayer1值,然后重新繪制(repaint),就更新了棋盤界面。由于游戲的功能簡單,也為了使游戲的操作盡可能的簡便,我不在游戲進(jìn)入時設(shè)計菜單,而是直接開始對戰(zhàn),在對戰(zhàn)界面,設(shè)置了重新開始和退出的按鈕。即運行即玩,一鍵開始,一鍵重來,一鍵退出。
玩家切換:棋類游戲有一個問題需要注意,就是提示當(dāng)前由哪方下棋,為了節(jié)省界面空間,簡化游戲界面,我在棋盤外圍加了一個3個像素寬的框,框的顏色就是當(dāng)前下棋方的顏色,如圖:
應(yīng)用程序類:Gobang.java
接下來就開始完成游戲中的每一個類,首先就是一個MIDlet類。Gobang類繼承自MIDlet類,用于連接設(shè)備的應(yīng)用程序管理器(Application Manager),通過方法startApp,pauseApp,destroyApp來通知游戲的開始,暫停和銷毀結(jié)束。源代碼如下:
package com.occo.j2me.game.gobang;
import javax.microedition.lcdui.Display;
import javax.microedition.midlet.MIDlet;
public class Gobang extends MIDlet {
GobangCanvas gobang;//定義游戲界面的Canvas類GobangCanvas的對象gobang
public Gobang() {
super();
gobang=new GobangCanvas(this);//生成GobangCanvas類的對象gobang
}
protected void startApp(){
Display.getDisplay(this).setCurrent(gobang);
//在屏幕上繪出游戲見面gobang
}
protected void pauseApp(){
}
protected void destroyApp(boolean arg0){
}
}
游戲界面類:GobangCanvas.java
GobangCanvas類是游戲的核心類,繼承自Canvas,此類將完成游戲的邏輯、繪圖、控制、互動等所有功能,此類的框架代碼如下:
package com.occo.j2me.game.gobang;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Graphics;
public class GobangCanvas extends Canvas implements CommandListener{
protected Gobang gobang;
public GobangCanvas(){
}
public GobangCanvas(Gobang gobang){
this.gobang=gobang;
}
protected void paint(Graphics g) {
}
}
棋子類:Chesses.java
此類定義了一個棋子,棋盤上的每一個棋子都對應(yīng)著一個Chesses的對象,整個棋盤是一個Chesses類型的二維數(shù)組,源代碼如下:
package com.occo.j2me.game.gobang;
public class Chesses {
boolean isPlayer1;
public Chesses() {
}
public Chesses(boolean isPlayer1) {
this.isPlayer1=isPlayer1;
}
}
添加圖形圖像
到現(xiàn)在,我們已經(jīng)完成了游戲的一個基本框架,接下來,我們就可以來繪制游戲的每一個部件了
首先是五子棋的一些初始設(shè)置,添加如下代碼到GobangCanvas.java
...
int empty;//游戲界面到屏幕邊緣的留空
int canvasW,canvasH;//畫布的長和寬
int chessLength;//棋子的直徑
int chessMapLength,chessMapGrid,chessGridLength;
//棋盤的邊長,棋盤一邊格子數(shù),每格寬度
int chessMapX,chessMapY;//棋盤左上角x,y坐標(biāo)
int selectedX,selectedY;//選擇框在棋盤格局上的x,y位置
boolean isPlayer1;//是否是玩家1
Chesses[][] chesses;//棋子數(shù)組
boolean newGame;//是否是新的游戲
public GobangCanvas(Gobang gobang){
newGame=true;
empty=10;
canvasW=getWidth()-empty;canvasH=getHeight()-empty;
chessMapGrid=15;
chesses=new Chesses[chessMapGrid+1][chessMapGrid+1];
if(canvasW>canvasH){
chessMapLength=canvasH-canvasH%chessMapGrid;
chessMapX=(canvasW-chessMapLength)/2+empty/2;
chessMapY=(canvasH%chessMapGrid)/2+empty/2;
}
else{
chessMapLength=canvasW-canvasW%chessMapGrid;
chessMapX=(canvasW%chessMapGrid)/2+empty/2;
chessMapY=(canvasH-chessMapLength)/2+empty/2;
}
chessGridLength=chessMapLength/chessMapGrid;
chessLength=chessGridLength-1;
selectedX=selectedY=chessMapGrid/2;
isPlayer1=true;
}
最先要繪制的是棋盤,棋盤是正方形,但屏幕有矩形的,所以棋盤邊長要按短邊計,但短邊未必是棋盤格子數(shù)的整數(shù)倍,因此
棋盤邊長 = 短邊 - 短邊 % 格子數(shù)
因為棋盤要居中,所以在算左上角坐標(biāo)時,記得也要把留空(empty)除以2,以下是畫棋盤的代碼:
protected void paintMap(Graphics g){
for(int i=0;i<chessMapGrid;i++){
for(int j=0;j<chessMapGrid;j++){
g.setColor(128,128,128);
g.drawRect(chessMapX+j*chessGridLength,
chessMapY+i*chessGridLength,
chessGridLength,chessGridLength);
}
}
}
然后是繪制選擇框,注意:選擇框的selectedX,selectedY并不是在畫布上的x,y坐標(biāo),而是在棋子數(shù)組(chesses)中的位置,源代碼如下:
protected void paintSelected(Graphics g){
g.setColor(0,0,255);
g.drawRect(chessMapX+selectedX*chessGridLength-chessGridLength/2,
chessMapY+selectedY*chessGridLength-chessGridLength/2,
chessGridLength,chessGridLength);
}
接著是按照棋子二維數(shù)組繪制已經(jīng)下了的棋子。玩家每下一次棋,就修改數(shù)組,在重新繪圖的時候就能繪出,源代碼如下:
protected void paintChesses(Graphics g){
for(int i=0;i<=chessMapGrid;i++){
for(int j=0;j<=chessMapGrid;j++){
if(chesses[i][j]!=null){
if(chesses[i][j].isPlayer1)
g.setColor(255,255,255);
else
g.setColor(255,0,0);
g.fillArc(chessMapX+j*chessGridLength-chessLength/2,
chessMapY+i*chessGridLength-chessLength/2,
chessLength,chessLength,0,360);
}
}
}
}
最后是繪制玩家提示框,并且把所有部件的繪制匯總在paint()方法中,注意繪制的順序,顯而易見,應(yīng)該先繪制提示框-棋盤-選擇框-棋子:
protected void paintPlayer(Graphics g,boolean isPlayer1){
if(isPlayer1)
g.setColor(255,255,255);
else
g.setColor(255,0,0);
g.drawRect(1,1,getWidth()-2,getHeight()-2);
g.drawRect(2,2,getWidth()-4,getHeight()-4);
g.drawRect(3,3,getWidth()-6,getHeight()-6);
}
protected void paint(Graphics g) {
g.setColor(0x00000000);
g.fillRect(0, 0, getWidth(), getHeight());
paintPlayer(g,isPlayer1);
paintMap(g);
paintSelected(g);
paintChesses(g);
}
響應(yīng)玩家操作
接下來應(yīng)該添加命令按鈕和游戲操作控制。我們在游戲中需要有兩個按鈕,重新開始和退出,此外還必須接收玩家控制選擇框的操作上下左右和著棋,添加代碼到GobangCanvas.java:
Command exitCmd;
Command restartCmd;
public GobangCanvas(Gobang gobang){
...
restartCmd = new Command("重新開始", Command.SCREEN, 0);
exitCmd = new Command("退出", Command.EXIT, 0);
addCommand(restartCmd);
addCommand(exitCmd);
setCommandListener(this);
}
private void init(){
if(newGame){
chesses=new Chesses[chessMapGrid+1][chessMapGrid+1];
isPlayer1=true;
selectedX=selectedY=chessMapGrid/2;
}
}
public void commandAction(Command c, Displayable d) {
if (c == exitCmd) {
gobang.destroyApp(false);
gobang.notifyDestroyed();
}else if(c==restartCmd){
init();//初始化棋盤,把棋盤清空,重新開始游戲
repaint();
}
}
protected synchronized void keyPressed(int keyCode) {
int action = getGameAction(keyCode);
if (action == Canvas.LEFT ) {
selectedX=(--selectedX+chessMapGrid+1)%(chessMapGrid+1);
}
else if (action == Canvas.RIGHT) {
selectedX=(++selectedX)%(chessMapGrid+1);
}
else if (action == Canvas.UP) {
selectedY=(--selectedY+chessMapGrid+1)%(chessMapGrid+1);
}
else if (action == Canvas.DOWN) {
selectedY=(++selectedY)%(chessMapGrid+1);
}
else if (action == Canvas.FIRE) {
if(chesses[selectedY][selectedX]==null){
chesses[selectedY][selectedX]=new Chesses(this.isPlayer1);
//checkWin();
this.isPlayer1=!this.isPlayer1;//切換下棋方
}
}
repaint();
}
private void checkWin(){
}
至此,游戲的所有繪圖部分全都給出,有一點需要指出,雙緩沖顯示技術(shù),由于現(xiàn)在有的手機已直接內(nèi)置了雙緩沖,這里我們就不在詳細(xì)說明,有興趣可以查閱相關(guān)文檔。
游戲輸贏
最后要說的是判斷游戲的輸贏,在游戲的響應(yīng)玩家操作部分,我留有一個方法checkWin(),大家可以自己思考設(shè)計算法來判斷游戲的輸贏,其實不要也無所謂,因為既然是兩個人類在下棋,輸贏一眼就看出來了。
總結(jié)
整個游戲已經(jīng)全部完成,大家一定會覺得很簡單吧,這個游戲其實只使用了j2me-midp1.0種很少的內(nèi)容,但已經(jīng)是一個完整的游戲了,希望對一些朋友有所幫助。當(dāng)然我們完全可以進(jìn)行一些擴展,比如加上片頭動畫,加上聲音,加上電腦AI,加上藍(lán)牙對戰(zhàn)功能(已經(jīng)完成,下次專門寫一篇文檔),這樣游戲就慢慢的完善,并且具有商業(yè)價值,愿大家學(xué)J順利,多多交流(MSN:yinowl@163.com QQ:47599318 E-mail:yinowl@163.com)。