用JAVA设计游戏:贪吃蛇游戏
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();
}
}
-