今天无聊了,自己弄了个贪吃蛇的游戏。很早以前就有这个愿望,可惜一直没有时间,今天终于弄好了,源代码如下:
实体类:
Snake.java
package com.nilaiya.snake.entities;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;

import com.nilaiya.snake.listener.SnakeListener;
import com.nilaiya.snake.util.Global;


/** *//**
* @author yellow
*
*/

public class Snake ...{

//判断蛇是否死掉
boolean lift;

//蛇的最后一个节点
private Point oldTail;

//表示方向的常量
public static final int UP = -1;

public static final int DOWN = 1;

public static final int LEFT = 2;

public static final int RIGHT = -2;

//保存蛇的方向
private int oldDirection, newDirection;

//保存蛇的所有坐标,用集合表示
private LinkedList<Point> body = new LinkedList<Point>();

//蛇的监听器,可以注册多个监听器
private Set<SnakeListener> listeners = new HashSet<SnakeListener>();


/** *//**
* 构造器
*
*/

public Snake() ...{
init();
}


/** *//**
* 蛇死掉的方法
*
*/

public void die() ...{
lift = false;
System.out.println("蛇死掉了!");
}


/** *//**
* 得到蛇头的坐标
* @return Point
* @return the body.getFirst()
*/

public Point getHead() ...{
return body.getFirst();
}


/** *//**
* 初始化蛇
*
*/

public void init() ...{
int x = Global.WIDTH / 2;
int y = Global.HEIGHT / 2;

for (int i = 0; i < 3; i++) ...{
body.addLast(new Point(x--, y));//蛇头在右边(最中间)
}
//蛇头默认移动方向向右
oldDirection = newDirection = RIGHT;

lift = true;//蛇一开始是活的
}


/** *//**
* 添加监听器的方法
* @param l
*/

public void addSnakeListener(SnakeListener l) ...{

if (l != null) ...{
this.listeners.add(l);
}
}


/** *//**
* 蛇的移动方法
*
*/

public void move() ...{
System.out.println("蛇移动了!");

if (!(oldDirection + newDirection == 0)) ...{
oldDirection = newDirection;
}
//1.去掉尾部
oldTail = body.removeLast();

//得到蛇头的坐标
int x = body.getFirst().x;
int y = body.getFirst().y;

//根据方向计算蛇头的新坐标

switch (oldDirection) ...{
case UP:
y--;

if (y < 0) ...{
y = Global.HEIGHT - 1;
}
break;
case DOWN:
y++;

if (y >= Global.HEIGHT) ...{
y = 0;
}
break;
case LEFT:
x--;

if (x < 0) ...{
x = Global.WIDTH - 1;
}
break;
case RIGHT:
x++;

if (x >= Global.WIDTH) ...{
x = 0;
}
break;
}
//新的蛇头坐标
Point newHead = new Point(x, y);
//2.加头
body.addFirst(newHead);
}


/** *//**
* 蛇改变方向的方法
* @param direction
*/

public void changeDirection(int direction) ...{
System.out.println("蛇改变方向了!");
newDirection = direction;
}


/** *//**
* 蛇吃食物的方法
*
*/

public void eatFood() ...{
System.out.println("蛇吃食物了!");

body.addLast(oldTail);
}


/** *//**
* 判断蛇是否吃到了自己的身体
* @return boolean
*/

public boolean isEatBody() ...{
System.out.println("蛇吃到自己的身体了!");


for (int i = 1; i < body.size(); i++) ...{

if (body.get(i).equals(this.getHead())) ...{
return true;
}
}
return false;
}


/** *//**
* 显示蛇的方法
* @param g
*/

public void drawMe(Graphics g) ...{
System.out.println("显示蛇的方法");
g.setColor(Color.BLUE);
//填充格子

for (Point p : body) ...{
g.fill3DRect(p.x * Global.CELL_SIZE, p.y * Global.CELL_SIZE,
Global.CELL_SIZE, Global.CELL_SIZE, true);
}

}


/** *//**
* 内部类
* 蛇一开始要不停的移动
* @author yellow
*
*/

private class SnakeMove implements Runnable ...{


public void run() ...{

while (lift) ...{
move();
//循环所有的遍历

for (SnakeListener l : listeners) ...{
l.snakeMoved(Snake.this);
}

try ...{
Thread.sleep(300);

} catch (InterruptedException e) ...{
e.printStackTrace();
System.out.println("线程延迟出错!");
}
}
}
}


/** *//**
* 启动线程的方法
*
*/

public void start() ...{
new Thread(new SnakeMove()).start();
}
}
Food.java
package com.nilaiya.snake.entities;

import java.awt.Graphics;
import java.awt.Point;

import com.nilaiya.snake.util.Global;


/** *//**
* @author yellow
*
*/

public class Food extends Point ...{

private static final long serialVersionUID = 1L;


/** *//**
* 放食物的坐标方法
* @param p
*/

public void newFood(Point p) ...{
this.setLocation(p);
}


/** *//**
* 判断蛇是否吃到了食物
* @param snake
* @return boolean
* @return this.equals(snake.getHead())
*/

public boolean isSnakeEatFood(Snake snake) ...{
System.out.println("蛇吃到了食物!");
return this.equals(snake.getHead());
}


/** *//**
* 显示食物的方法
* @param g
*/

public void drawMe(Graphics g) ...{
System.out.println("显示食物!");
g.fill3DRect(x * Global.CELL_SIZE, y * Global.CELL_SIZE,
Global.CELL_SIZE, Global.CELL_SIZE, true);
}
}
Ground.java
package com.nilaiya.snake.entities;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.Random;

import com.nilaiya.snake.util.Global;


/** *//**
* @author yellow
*
*/

public class Ground ...{

//用数组来保存石头
private int[][] rockes = new int[Global.WIDTH][Global.HEIGHT];


/** *//**
* 构造器
*
*/

public Ground() ...{

for (int x = 0; x < Global.WIDTH; x++) ...{
rockes[x][0] = 1;
rockes[x][Global.HEIGHT - 1] = 1;
}
}


/** *//**
* 食物随机产生
* @return Point
* @return the new Point(x, y)
*/

public Point getPoint() ...{
Random random = new Random();
int x = 0;
int y = 0;

do ...{
x = random.nextInt(Global.WIDTH);
y = random.nextInt(Global.HEIGHT);
} while (rockes[x][y] == 1);
return new Point(x, y);
}


/** *//**
* 判断蛇吃否吃到了石头
* @param snake
* @return boolean
*/

public boolean isSnakeEatRock(Snake snake) ...{
System.out.println("蛇吃到了石头!");


for (int x = 0; x < Global.WIDTH; x++) ...{

for (int y = 0; y < Global.HEIGHT; y++) ...{
if (rockes[x][y] == 1

&& (x == snake.getHead().x && y == snake.getHead().y)) ...{
return true;
}
}
}
return false;
}


/** *//**
* 显示石头的方法
* @param g
*/

public void drawMe(Graphics g) ...{
System.out.println("显示石头的方法!");

g.setColor(Color.DARK_GRAY);

//画石头

for (int x = 0; x < Global.WIDTH; x++) ...{

for (int y = 0; y < Global.HEIGHT; y++) ...{

if (rockes[x][y] == 1) ...{
g.fill3DRect(x * Global.CELL_SIZE, y * Global.CELL_SIZE,
Global.CELL_SIZE, Global.CELL_SIZE, true);
}
}
}
}
}
视图类
GamePanel.java
package com.nilaiya.snake.view;

import java.awt.Color;
import java.awt.Graphics;

import javax.swing.JPanel;

import com.nilaiya.snake.entities.Food;
import com.nilaiya.snake.entities.Ground;
import com.nilaiya.snake.entities.Snake;
import com.nilaiya.snake.util.Global;


/** *//**
* @author yellow
*
*/

public class GamePanel extends JPanel ...{

private static final long serialVersionUID = 1L;

// 定义对象
private Snake snake;

private Food food;

private Ground ground;


/** *//**
* GamePanel的显示方法
*
* @param snake
* @param food
* @param ground
*/

public void display(Snake snake, Food food, Ground ground) ...{
System.out.println("GamePanel 显示了");
this.snake = snake;
this.food = food;
this.ground = ground;

this.repaint();// 这个方法调用paintComponent()方法重新显示
}


/** *//**
* 重新显示的方法
*/
@Override

protected void paintComponent(Graphics g) ...{
// 重新显示
g.setColor(new Color(0xcfcfcf));
g.fillRect(0, 0, Global.WIDTH * Global.CELL_SIZE, Global.HEIGHT
* Global.CELL_SIZE);

if (snake != null && ground != null && food != null) ...{
this.snake.drawMe(g);
this.food.drawMe(g);
this.ground.drawMe(g);
}
}
}
Globale.java
package com.nilaiya.snake.util;


/** *//**
* @author yellow
*
*/

public class Global ...{

// 格子的参数 高 、 宽
// 一个格子的宽度
public static final int CELL_SIZE = 20;

// 整个显示区域的大小
public static final int WIDTH = 20;

public static final int HEIGHT = 20;

}
控制、事件监听类
Controller.java
package com.nilaiya.snake.controller;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import com.nilaiya.snake.entities.Food;
import com.nilaiya.snake.entities.Ground;
import com.nilaiya.snake.entities.Snake;
import com.nilaiya.snake.listener.SnakeListener;
import com.nilaiya.snake.view.GamePanel;


/** *//**
* @author yellow
*
*/

public class Controller extends KeyAdapter implements SnakeListener ...{
// 定义对象
private Snake snake;

private Food food;

private Ground ground;

private GamePanel gamePanel;


/** *//**
* 构造器
*
* @param snake
* @param food
* @param ground
* @param gamePanel
*/

public Controller(Snake snake, Food food, Ground ground, GamePanel gamePanel) ...{
super();
this.snake = snake;
this.food = food;
this.ground = ground;
this.gamePanel = gamePanel;
}


/** *//**
* 开始新游戏的方法
*
*/

public void newGame() ...{
snake.start();
food.newFood(ground.getPoint());
}


/** *//**
* 显示蛇、石头、食物
*/

public void snakeMoved(Snake snake) ...{
// 如果吃到了食物

if (food.isSnakeEatFood(snake)) ...{
snake.eatFood();
food.newFood(ground.getPoint());
}
// 如果吃到了石头

if (ground.isSnakeEatRock(snake)) ...{
snake.die();// 游戏就结束
}
// 如果吃到自己的身体

if (snake.isEatBody()) ...{
snake.die();// 游戏就结束
}

gamePanel.display(snake, food, ground);
}


/** *//**
* 覆盖KeyAdapter的keyPressed()方法
*/
@Override

public void keyPressed(KeyEvent e) ...{
// 改变蛇的方向

switch (e.getKeyCode()) ...{
case KeyEvent.VK_UP:
snake.changeDirection(Snake.UP);
break;
case KeyEvent.VK_DOWN:
snake.changeDirection(Snake.DOWN);
break;
case KeyEvent.VK_LEFT:
snake.changeDirection(Snake.LEFT);
break;
case KeyEvent.VK_RIGHT:
snake.changeDirection(Snake.RIGHT);
break;
}
}
}
SnakeListener .java
package com.nilaiya.snake.listener;

import com.nilaiya.snake.entities.Snake;


/** *//**
* @author yellow
*
*/

public interface SnakeListener ...{


/** *//**
* 蛇移动的方法,蛇每移动一次就触发这个事件
*
* @param snake
*/
void snakeMoved(Snake snake);
}
游戏测试类,包含了main()函数
GameTest.java
package com.nilaiya.snake.gametest;

import java.awt.BorderLayout;

import javax.swing.JFrame;

import com.nilaiya.snake.controller.Controller;
import com.nilaiya.snake.entities.Food;
import com.nilaiya.snake.entities.Ground;
import com.nilaiya.snake.entities.Snake;
import com.nilaiya.snake.util.Global;
import com.nilaiya.snake.view.GamePanel;


/** *//**
* @author yellow
*
*/

public class GameTest ...{


/** *//**
* main()方法,程序入口
*
* @param args
*/

public static void main(String[] args) ...{

// 实例化类
Snake snake = new Snake();
Food food = new Food();
Ground ground = new Ground();
GamePanel gamePanel = new GamePanel();

Controller controller = new Controller(snake, food, ground, gamePanel);

// 游戏窗口
JFrame frame = new JFrame("贪吃蛇-37#404工作小组出品-yellow");
//禁止窗口最大化
frame.setResizable(false);
// 关闭窗口就退出程序
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 设置大小
gamePanel.setSize(Global.WIDTH * Global.CELL_SIZE, Global.HEIGHT
* Global.CELL_SIZE);

frame.setSize(Global.WIDTH * Global.CELL_SIZE + 6, Global.HEIGHT
* Global.CELL_SIZE + 28);
// 添加gamePanel
frame.add(gamePanel, BorderLayout.CENTER);

// 注册监听器
gamePanel.addKeyListener(controller);
snake.addSnakeListener(controller);
// 给frame加上监听
frame.addKeyListener(controller);

// 显示游戏窗口
frame.setVisible(true);

// 开始游戏
controller.newGame();
}

}
本游戏的开发环境为MyEclipse 5.1 + jdk1.5。本游戏是按照MVC模块开发的。其中:
Snake.java,Food.java,Ground.java 为MVC的M部分既是模型部分。
GamePanel.java,Grobal.java为MVC的M部分既是视图部分,主要用来显示游戏的窗体。
Controller.java,SnakeListener .java为MVC的C部分,既是控制器,还有处理相关的逻辑代码。
GameTest.java 为游戏的测试类,此类为测试游戏。
该游戏还有许多的bug和不足之处,还望大家指出,谢谢。