用JAVA设计游戏:贪吃蛇游戏

MVC实现的贪吃蛇游戏有四类。运行GreedSnake即可。主要是观察者模式的使用,我加了很多评论。

1、

/*

*程序名称:Snake

*原作者:BigF

*修改者:算法

*描述:我之前也是用C写的这个程序,但是现在看到BigF用Java写的这个程序,我发现虽然作者自称是Java初学者,

*但显然编程质量不错,程序结构写得很清楚,一些细微的地方也很简洁,是心血来潮。

*接下来我仔细看了这个程序,发现数据和性能分离的很好,最近在研究MVC设计模式。

*所以我尝试改变程序结构,用MVC模式实现,对源程序改动不大。

*同时,我也为我理解的节目补充了一些评论,希望对你阅读有所帮助。

*/

包mvcTest

/**

* @作者王宇

* @版本1.0

*描述:

* & lt/pre & gt;

创建日期:日期:2005-6-13时间:15:57:16

*上次修改时间:

*历史:

*/

公共类GreedSnake {

公共静态void main(String[] args) {

SnakeModel模型= new SnakeModel(20,30);

SnakeControl control =新SnakeControl(型号);

SnakeView视图= new SnakeView(模型,控件);

//添加一个观察者,使视图成为模型的观察者。

model.addObserver(视图);

(新线程(模型))。start();

}

}

-

2、

包mvcTest

//SnakeControl.java

导入Java . awt . event . key event;

导入Java . awt . event . key listener;

/**

* MVC中的控制器负责接收用户的操作,并将用户的操作告知模型。

*/

公共类SnakeControl实现KeyListener{

SnakeModel模型;

公共SnakeControl(SnakeModel模型){

this.model = model

}

公共void按键(按键事件e) {

int key code = e . get key code();

If (model.running){ //在运行状态下处理的按键。

开关(键码){

案例关键事件。VK_UP:

model . change direction(snake model。UP);

打破;

案例关键事件。VK _唐:

model . change direction(snake model。向下);

打破;

案例关键事件。VK _左:

model . change direction(snake model。左);

打破;

案例关键事件。VK右:

model . change direction(snake model。对);

打破;

案例关键事件。VK _添加:

案例关键事件。VK _第_页起:

model . speedup();

打破;

案例关键事件。VK减去:

案例关键事件。VK _下一页:

model . speed down();

打破;

案例关键事件。VK _空间:

案例关键事件。VK_P:

model . changepousestate();

打破;

默认值:

}

}

//无论如何,密钥被处理,导致游戏重启。

if (keyCode == KeyEvent。VK_R ||

keyCode == KeyEvent。VK_S ||

keyCode == KeyEvent。VK _回车){

model . reset();

}

}

public void key released(key event e){

}

公共void键入的(KeyEvent e) {

}

}

-

3、

/*

*

*/

包mvcTest

/**

*游戏的模型类,负责所有游戏相关的数据和操作。

* @作者王宇

* @版本1.0

*描述:

* & lt/pre & gt;

创建时间:日期:2005-6-13时间:15:58:33

*上次修改时间:

*历史:

*/

//SnakeModel.java

导入javax . swing . *;

导入Java . util . arrays;

导入Java . util . linked list;

导入Java . util . observable;

导入Java . util . random;

/**

*游戏的模型类,负责所有游戏相关的数据和操作。

*/

SnakeModel类扩展了Observable实现Runnable {

布尔[][]矩阵;//指示该位置是否有蛇或食物。

linked list node array = new linked list();//蛇身

节点食物;

int maxX

int maxY

int direction = 2;//蛇跑的方向

布尔运行=假;//运行状态

int timeInterval = 200//时间间隔,毫秒

double speedChangeRate = 0.75//一次速度变化率

布尔暂停=假;//暂停标志

int得分= 0;//分数

int count move = 0;//吃食物前移动的次数

//上下应该是偶数

//右和左应该是奇数

public static final int UP = 2;

public static final int DOWN = 4;

public static final int LEFT = 1;

public static final int RIGHT = 3;

public SnakeModel( int maxX,int maxY) {

this.maxX = maxX

this.maxY = maxY

reset();

}

公共void重置(){

方向= SnakeModel。向上;//蛇跑的方向

timeInterval = 200//时间间隔,毫秒

暂停=假;//暂停标志

得分= 0;//分数

count move = 0;//吃食物前移动的次数

//initialimatirx,全部清零。

matrix = new boolean[maxX][];

for(int I = 0;我& ltmaxX++i) {

matrix[I]= new boolean[maxY];

Arrays.fill(matrix[i],false);

}

//蛇的首字母

//初始化蛇。如果横向位置超过20个,则长度为10;否则就是水平位置的一半。

int initArrayLength = maxX & gt20 ?10:maxX/2;

node array . clear();

for(int I = 0;我& ltinitArrayLength++i) {

int x = maxX/2+I;//maxX初始化为20。

int y = maxY/2;//maxY初始化为30。

//nodeArray[x,y]: [10,15]-[11,15]-[12,15]~~[20,15]

//默认运行方向是向上的,所以在游戏开始的时候,nodeArray就变成了:

// [10,14]-[10,15]-[11,15]-[12,15]~~[19,15]

nodeArray.addLast(新节点(x,y));

matrix[x][y]= true;

}

//创建食物

food = create food();

matrix[food . x][food . y]= true;

}

public void change direction(int new direction){

//更改的方向不能与原始方向相同或相反。

如果(方向% 2!= newDirection % 2) {

direction = newDirection

}

}

/**

*运行一次

* @返回

*/

公共布尔moveOn() {

Node n =(Node)Node array . get first();

int x = n.x

int y = n.y

//根据方向增加或减少坐标值

开关(方向){

案例向上:

y-;

打破;

案例向下:

y++;

打破;

案例左侧:

x-;

打破;

案例权利:

x++;

打破;

}

//如果新坐标在有效范围内,则对其进行处理。

如果((0 & lt= x & amp& ampx & ltmaxX)和amp& amp(0 & lty & amp& ampy & ltmaxY)) {

If (matrix[x][y]) {//如果新坐标点有东西(蛇或者食物)。

if(x = = food . x & amp;& ampY == food.y) {//吃下食物,成功。

nodeArray.addFirst(食物);//给蛇头一个长长的礼物。

//分数法则与移动改变方向的次数和速度有关。

int score get =(10000-200 * count move)/time interval;

score+= score get & gt;0 ?score get:10;

count move = 0;

food = create food();//创造新的食物

matrix[food . x][food . y]= true;//设置食物的位置。

返回true

} else //吃蛇本身,失败。

返回false

} else {//如果新坐标点没有东西(蛇),移动蛇。

nodeArray.addFirst(新节点(x,y));

matrix[x][y]= true;

n =(Node)Node array . remove last();

matrix[n . x][n . y]= false;

count move++;

返回true

}

}

返回false//碰了边线,失败

}

公共无效运行(){

跑步=真;

(跑步时){

尝试{

Thread.sleep(时间间隔);

} catch(异常e) {

打破;

}

如果(!暂停){

if (moveOn()) {

set changed();//模型通知视图数据已经更新。

notify observers();

}否则{

JOptionPane.showMessageDialog(空,

“你失败了”,

“游戏结束”,

JOptionPane。信息_消息);

打破;

}

}

}

跑步=假;

}

私有节点createFood() {

int x = 0;

int y = 0;

//随机获取有效区域内不与蛇和食物重叠的位置。

做{

Random r = new Random();

x = r . nextint(maxX);

y = r . nextint(maxY);

} while(matrix[x][y]);

返回新节点(x,y);

}

公共void加速(){

timeInterval * = speedChangeRate

}

公共void减速(){

time interval/= speed change rate;

}

public void changePauseState() {

暂停了=!暂停;

}

公共字符串toString() {

字符串结果= " ";

for(int I = 0;我& ltnode array . size();++i) {

Node n =(Node)Node array . get(I);

result += "[" + n.x +","+n . y+"]";

}

返回结果;

}

}

类节点{

int x;

int y;

Node(int x,int y) {

this.x = x

this.y = y

}

}

-

4、

包mvcTest

//SnakeView.java

导入javax . swing . *;

导入Java . awt . *;

导入Java . util . iterator;

导入Java . util . linked list;

导入Java . util . observable;

导入Java . util . observer;

/**

* MVC模式下的Viewer只负责显示数据,不考虑游戏的控制逻辑。

*/

公共类SnakeView实现Observer {

SnakeControl控件= null

SnakeModel模型= null

JFrame主机;

画布paintCanvas

JLabel labelScore

public static final int canvas width = 200;

public static final int canvasHeight = 300;

公共静态final int node width = 10;

public static final int nodeHeight = 10;

公共SnakeView(SnakeModel模型,SnakeControl控件){

this.model = model

this.control = control

mainFrame = new JFrame(" GreedSnake ");

container CP = mainframe . getcontentpane();

//在顶部创建分数显示

labelScore = new JLabel(" Score:");

cp.add(labelScore,BorderLayout。北);

//创建中间游戏显示区。

paintCanvas =新画布();

paint canvas . setsize(canvas width+1,canvas height+1);

paintCanvas.addKeyListener(控件);

cp.add(paintCanvas,BorderLayout。中心);

//创建下面的帮助栏。

JPanel panel buttom = new JPanel();

panel buttom . set layout(new BorderLayout());

JLabel labelHelp

labelHelp = new JLabel("PageUp,PageDown表示速度;,JLabel。中心);

panel button . add(label help,BorderLayout。北);

labelHelp = new JLabel("ENTER或R或S表示开始;",JLabel。中心);

panel button . add(label help,BorderLayout。中心);

labelHelp = new JLabel("空格或P表示暂停",JLabel。中心);

panel button . add(label help,BorderLayout。南);

CP . add(panel button,BorderLayout。南);

mainFrame.addKeyListener(控件);

大型机. pack();

mainframe . setresizable(false);

mainframe . setdefaultcloseoperation(JFrame。EXIT _ ON _ CLOSE);

mainframe . set visible(true);

}

void repaint() {

graphics g = paint canvas . get graphics();

//绘制背景

g.setColor(颜色。白色);

g.fillRect(0,0,canvasWidth,canvas height);

//画蛇

g.setColor(颜色。黑色);

linked list na = model . node array;

迭代器it = na . iterator();

while (it.hasNext()) {

节点n =(Node)it . next();

drawNode(g,n);

}

//画出食物

g.setColor(颜色。红色);

Node n = model.food

drawNode(g,n);

update score();

}

私有void drawNode(图形g,节点n) {

g.fillRect(n.x * nodeWidth,

n.y * nodeHeight,

节点宽度- 1,

nodeHeight-1);

}

public void updateScore() {

string s = " Score:"+model . Score;

labelScore.setText

}

公共void更新(Observable o,Object arg) {

repaint();

}

}

-