概述
相信大家都玩过Nokia手机上的贪吃蛇游戏。在该游戏中,玩家操纵一条贪吃的蛇在迷宫里行走,贪吃蛇按玩家所按的方向键折行,蛇头吃到各种食物(比如大力丸)后,会有各种反应(比如蛇身变长),如果贪吃蛇碰上墙壁或者自身的话,就GameOver了(当然也可能是减去一条生命)。要实现该游戏其实并不麻烦,关键就是要找到一个合适的核心算法。本文就给出一个参考实现,你可以基于该demo做扩展。要说明的一点是:本文只演示最核心的算法,要实现一个完整的游戏,你还需要做很多的扩展,重构。
实例代码
该程序包括3个java文件。一个是SnakeMIDlet,另外2个分别是一个Canvas(SnakeCanvas)和一个代表贪吃蛇的类Snake
SnakeMIDlet.java
importjavax.microedition.lcdui.Display;
importjavax.microedition.midlet.MIDlet;
importjavax.microedition.midlet.MIDletStateChangeException;
/**
*@authorJagie
*/
publicclassSnakeMIDletextendsMIDlet{
protectedvoidstartApp()throwsMIDletStateChangeException{
//TODOAuto-generatedmethodstub
Display.getDisplay(this).setCurrent(newSnakeCanvas());
}
/*(non-Javadoc)
*@seejavax.microedition.midlet.MIDlet#pauseApp()
*/
protectedvoidpauseApp(){
//TODOAuto-generatedmethodstub
}
/*(non-Javadoc)
*@seejavax.microedition.midlet.MIDlet#destroyApp(boolean)
*/
protectedvoiddestroyApp(booleanarg0)throwsMIDletStateChangeException{
//TODOAuto-generatedmethodstub
}
}
SnakeCanvas.java
importjavax.microedition.lcdui.Canvas;
importjavax.microedition.lcdui.Graphics;
/**
*@authorJagie
*
*/
publicclassSnakeCanvasextendsCanvasimplementsRunnable{
Snakesnake=newSnake();
SnakeCanvas(){
snake.init();
}
protectedvoidpaint(Graphicsg){
g.setColor(0);
g.fillRect(0,0,this.getWidth(),this.getHeight());
snake.paint(g);
}
/**
*游戏主线程,驱动蛇移动
*/
publicvoidrun(){
while(true){
snake.move();
repaint();
try{
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
}
/**
*按键相应,产生新蛇头
*/
protectedvoidkeyPressed(intc){
intga=this.getGameAction(c);
switch(ga){
caseCanvas.UP:
snake.breakInto(1);
break;
caseCanvas.DOWN:
snake.breakInto(3);
break;
caseCanvas.LEFT:
snake.breakInto(4);
break;
caseCanvas.RIGHT:
snake.breakInto(2);
break;
}
}
}
Snake.java
importjavax.microedition.lcdui.Graphics;
/**
*
*@authorJagie
*贪吃蛇
*/
publicclassSnake{
//蛇环节,每个环节为一个int[]sec
//sec[0]:环节起点x,sec[1]:环节起点y,sec[2]:环节方向,sec[3]:环节长度
/**
*初始化sections
*开始的时候,整条蛇只有一段。
*
*/
publicvoidinit(){
int[]head={10,10,2,50};
sections.addElement(head);
}
/**
*绘制
*@paramg
*/
publicsynchronizedvoidpaint(Graphicsg){
if(sections.isEmpty()){
return;
}
g.setColor(0,255,0);
for(inti=0;i int[]sec=(int[])sections.elementAt(i); //sec[0]:起点x,sec[1]:起点y,sec[2]:方向,sec[3]:长度 switch(sec[2]){ case1: g.drawLine(sec[0],sec[1],sec[0],sec[1]-sec[3]); break; case2: g.drawLine(sec[0],sec[1],sec[0]+sec[3],sec[1]); break; case3: g.drawLine(sec[0],sec[1],sec[0],sec[1]+sec[3]); break; case4: g.drawLine(sec[0],sec[1],sec[0]-sec[3],sec[1]); break; } } } /** * *@authorJagie * *蛇的爬行。本质上是蛇头长度++,蛇尾长度--.同时移动蛇尾起点。如果蛇尾长度小于0,则去掉蛇尾。 */ publicsynchronizedvoidmove(){ if(sections.isEmpty()){ return; } //蛇尾 int[]tail=(int[])sections.elementAt(sections.size()-1); //蛇头 int[]head=(int[])sections.elementAt(0); //根据蛇尾环节的方向移动蛇尾。 switch(tail[2]){ case1: tail[1]--; break; case2: tail[0]++; break; case3: tail[1]++; break; case4: tail[0]--; break; } //蛇尾缩短 tail[3]--; //蛇头增长 head[3]++; //蛇尾<0,则去掉蛇尾 if(tail[3]<=0){ sections.removeElement(tail); } } /** *蛇分段 *@paramdir新蛇头的方向 */ publicsynchronizedvoidbreakInto(intdir){ if(sections.isEmpty()){ return; } int[]head=(int[])sections.elementAt(0); //新蛇头方向和旧蛇头方向一致,则无反应。 //TODO可以考虑加速。 if(dir==head[2]){ return; } //增加新蛇头 int[]newhead=newint[4]; //新蛇头的起始位置,与旧蛇头的运动方向有关。 switch(head[2]){ case1: newhead[0]=head[0]; newhead[1]=head[1]-head[3]; newhead[2]=dir; newhead[3]=0; //蛇头总是第一个元素 sections.insertElementAt(newhead,0); break; case2: newhead[0]=head[0]+head[3]; newhead[1]=head[1]; newhead[2]=dir; newhead[3]=0; sections.insertElementAt(newhead,0); break; case3: newhead[0]=head[0]; newhead[1]=head[1]+head[3]; newhead[2]=dir; newhead[3]=0; sections.insertElementAt(newhead,0); break; case4: newhead[0]=head[0]-head[3]; newhead[1]=head[1]; newhead[2]=dir; newhead[3]=0; sections.insertElementAt(newhead,0); break; } } } 小结 本文给出了一个简单的贪吃蛇的例子,演示了贪吃蛇游戏核心的一种参考算法 作者简介 陈万飞,网名Jagie,培训师,爱好java技术.可通过chen_cwf@163.