贪吃蛇游戏,参考着游戏功能文档写的,有些算法参考了现成的游戏代码,有些算法和想法也是自己想的和设计的,下面先说明下自己对这个游戏的想法:
游戏有三个类:
Cell:格子类,用语组成格子和食物,因为食物只是一个格子组成,所以不再新建类,new一个Cell代表食物
Worm:蛇类,实现蛇的基本功能:封装了蛇的动作,包括碰撞检查,吃食物和移动
WormStage:舞台类,实现整个游戏的功能
下面是完整的代码:
格子类:
1 package com; 2 3 import java.awt.Color; 4 /**格子类,最基本的类*/ 5 public class Cell { 6 private int row; 7 private int col; 8 private Color color; 9 10 public Cell(int row, int col, Color color) { 11 super(); 12 this.row = row; 13 this.col = col; 14 this.color = color; 15 } 16 17 public int getRow() { 18 return row; 19 } 20 21 public void setRow(int row) { 22 this.row = row; 23 } 24 25 public int getCol() { 26 return col; 27 } 28 29 public void setCol(int col) { 30 this.col = col; 31 } 32 33 public Color getColor() { 34 return color; 35 } 36 37 public void setColor(Color color) { 38 this.color = color; 39 } 40 41 @Override 42 public String toString() { 43 return "Cell [row=" + row + ", col=" + col + "]"; 44 } 45 46 }
Worm类:
1 package com; 2 3 import java.awt.Color; 4 import java.util.Arrays; 5 6 /** 蛇体类,封装了蛇的动作,包括检查碰撞,吃食物和移动 */ 7 public class Worm { 8 /** 移动数据 */ 9 private final int CHANGELEFT = -2; 10 private final int CHANGERIGHT = 2; 11 private final int CHANGEDOWN = -1; 12 private final int CHANGEUP = 1; 13 14 /** 蛇的颜色和蛇的初始长度 */ 15 private Color wormColor; 16 private Cell[] worm; 17 18 /** 构造器,用于初始化 */ 19 public Worm() { 20 worm = new Cell[3]; 21 wormColor = Color.red; 22 for (int i = 0; i < 3; i++) { 23 worm[i] = new Cell(5 - i, 10, Color.red); 24 } 25 26 } 27 28 /* get方法,用于别的类中调用worm */ 29 public Cell[] getWorm() { 30 return worm; 31 } 32 33 /** 判断碰撞算法 */ 34 public boolean isHit(int changeNum) { 35 Cell newHead = newHead(changeNum); 36 /* 如果新头不是蛇的第二节就进行碰撞算法 */ 37 if (newHead.getCol() != worm[1].getCol() 38 || newHead.getRow() != worm[1].getRow()) { 39 /* 看新头是否超出边界,超出则是发生碰撞 */ 40 if (newHead.getCol() < 0 || newHead.getCol() > 49 41 || newHead.getRow() < 0 || newHead.getRow() > 49) { 42 return true; 43 } 44 /* 遍历蛇身,与新头比较,看是否重合,如果重合就是发生碰撞 */ 45 for (Cell cell : worm) { 46 if (newHead.getCol() == cell.getCol() 47 && newHead.getRow() == cell.getRow()) { 48 return true; 49 } 50 } 51 } 52 53 return false; 54 } 55 56 /** 蛇的移动,传入两个参数,food表示食物,用于判断是否吃到食物,并返回,changeNum表示移动方向,0表示自动前进 */ 57 public boolean move(Cell food, int changeNum) { 58 boolean eat = false; 59 Cell newHead = newHead(changeNum); 60 61 if (newHead.getCol() == food.getCol() 62 && newHead.getRow() == food.getRow()) { 63 worm = Arrays.copyOf(worm, worm.length + 1); 64 65 eat = true; 66 67 } 68 /*如果新头不是蛇身的第二节,就移动*/ 69 if (newHead.getCol() != worm[1].getCol() 70 || newHead.getRow() != worm[1].getRow()) { 71 for (int i = worm.length - 1; i >= 1; i--) { 72 worm[i] = worm[i - 1]; 73 } 74 worm[0] = newHead; 75 76 } 77 return eat; 78 79 } 80 /**根据传入的参数,新生成一个新头,如果是0就是自动前进的新头*/ 81 public Cell newHead(int changeNum) { 82 Cell newHead = new Cell(-1, -1, wormColor); 83 Cell head = worm[0]; 84 Cell nextCell = worm[1]; 85 86 switch (changeNum) { 87 case 0: 88 newHead.setCol(head.getCol() * 2 - nextCell.getCol()); 89 newHead.setRow(head.getRow() * 2 - nextCell.getRow()); 90 break; 91 case CHANGELEFT: 92 newHead.setCol(head.getCol() - 1); 93 newHead.setRow(head.getRow()); 94 break; 95 case CHANGEDOWN: 96 newHead.setCol(head.getCol()); 97 newHead.setRow(head.getRow() + 1); 98 break; 99 case CHANGEUP: 100 newHead.setCol(head.getCol()); 101 newHead.setRow(head.getRow() - 1); 102 break; 103 104 case CHANGERIGHT: 105 newHead.setCol(head.getCol() + 1); 106 newHead.setRow(head.getRow()); 107 break; 108 109 } 110 111 return newHead; 112 } 113 114 }
WormStage类:
package com; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.Random; import javax.swing.JFrame; import javax.swing.JPanel; /** * 游戏的主界面 * * @author 陈杰 * */ public class WormStage extends JPanel { /** 食物,因为只有一个食物,所以定义为静态的,以后调用方法修改食物的位置,以节省资源 */ private static Cell food = new Cell(0, 0, Color.green);; /** 舞台的长宽和大小的数据,定义为常量 */ private static final int ROWS = 50; private static final int COLS = 50; private static final int SIZE = 10; /** 贪吃蛇 */ private Worm worm = new Worm(); /** 下面是转向用到的数据 */ private final int CHANGELEFT = -2; private final int CHANGERIGHT = 2; private final int CHANGEDOWN = -1; private final int CHANGEUP = 1; /** 分数:已经吃掉的食物总数 */ public static int score = 0; /** 游戏的状态,并没有设置暂停 */ private static int state; private static final int PLAYING = 0; private static final int GAMEOVER = 1; private static final String[] State = { "", "GameOver" }; /** 在舞台上,不包括蛇体位置,通过修改col和row随机产生一个食物 */ private void randomFood() { int col; int row; Random r = new Random(); /* 在舞台内随机指定一个食物的位置,直到产生的位置不在蛇身上 */ do { col = r.nextInt(COLS); row = r.nextInt(ROWS); } while (insideWorm(row, col)); /* 设置食物的位置 */ food.setCol(col); food.setRow(row); } /** 判断是否在蛇身上:用于随机产生食物判断 */ private boolean insideWorm(int row, int col) { for (Cell cell : worm.getWorm()) { if (cell.getRow() == row && cell.getCol() == col) return true; } return false; } /** 重写paint方法 */ public void paint(Graphics g) { paintStage(g);// 画出背景 paintFood(g);// 画出食物 paintWorm(g);// 画出蛇 paintState(g);// 画出游戏状态 paintScore(g);// 画出分数 } /** 分数的绘制方法 */ private void paintScore(Graphics g) { String str = "得分:" + score; String len = "贪吃蛇长度:" + worm.getWorm().length; g.setColor(Color.black); Font font = g.getFont(); Font f = new Font(font.getName(), font.getStyle(), 15); g.setFont(f); g.drawString(str, 325, 540); g.drawString(len, 325, 580); } /** 游戏状态的绘制方法 */ private void paintState(Graphics g) { g.setColor(Color.white); Font font = g.getFont(); Font f = new Font(font.getName(), font.getStyle(), 60); g.setFont(f); g.drawString(State[state], 100, 200); } /** 蛇的绘制方法 */ private void paintWorm(Graphics g) { /* 利用for循环,遍历蛇的所有组成cell并画出 */ for (Cell cell : worm.getWorm()) { g.setColor(cell.getColor()); g.fillRect(cell.getCol() * SIZE, cell.getRow() * SIZE, SIZE, SIZE); g.setColor(Color.black); g.drawRect(cell.getCol() * SIZE, cell.getRow() * SIZE, SIZE, SIZE); } } /** 食物的绘制方法 */ private void paintFood(Graphics g) { g.setColor(food.getColor()); g.fillRect(food.getCol() * SIZE, food.getRow() * SIZE, SIZE, SIZE); } /** 背景的绘制方法 */ private void paintStage(Graphics g) { g.setColor(Color.black); g.fillRect(0, 0, 500, 500); g.setColor(Color.white); g.fillRect(0, 500, 500, 100); g.setColor(Color.black); g.drawRect(0, 500, 499, 99); g.drawRect(0, 500, 299, 99); Font font = g.getFont(); Font f = new Font(font.getName(), font.getStyle(), 15); g.setFont(f); g.drawString("↑←↓→控制移动,[S]重新开始", 20, 540); g.drawString("[Q]退出游戏", 30, 580); } /** 封装移动和转向方法,如果传入0,则前进 */ private void moveAction(int changeNum) { /* 判断是否发生碰撞 */ if (worm.isHit(changeNum)) { /* 碰撞就结束游戏 */ state = GAMEOVER; } else { /* 否则,转向并判断是否吃到食物 */ if (worm.move(food, changeNum)) { /* 如果吃到就加分并随机产生一个食物 */ score++; randomFood(); } } } /** action方法,整个游戏的控制方法 */ private void action() throws Exception { /* 新建一个蛇 */ worm = new Worm(); /* 随机产生一个食物 */ randomFood(); /* 键盘控制:Q退出游戏;上下左右方向键控制蛇的移动;如果游戏结束,S重新开始游戏 */ KeyListener l = new KeyAdapter() { public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); if (key == KeyEvent.VK_Q) { System.exit(0); } /* 添加return,使得游戏结束,只有S键有效 */ if (state == GAMEOVER) { if (key == KeyEvent.VK_S) { restart(); } return; } switch (key) { case KeyEvent.VK_LEFT: moveAction(CHANGELEFT); break; case KeyEvent.VK_RIGHT: moveAction(CHANGERIGHT); break; case KeyEvent.VK_UP: moveAction(CHANGEUP); break; case KeyEvent.VK_DOWN: moveAction(CHANGEDOWN); break; } repaint(); } }; this.addKeyListener(l); this.requestFocus(); /* 死循环控制蛇的自动前进 */ while (true) { if (state == PLAYING) { moveAction(0); } repaint(); Thread.sleep(500); } } /** 重新开始方法 */ protected void restart() { /* 状态更改为PLAYING,new一个新的蛇,随机产生一个食物 */ state = PLAYING; worm = new Worm(); randomFood(); } /** main方法,画出框体,面板并调用action方法启动游戏 */ public static void main(String[] args) throws Exception { JFrame frame = new JFrame(); WormStage wormStage = new WormStage(); frame.setSize(500, 600); frame.add(wormStage); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setUndecorated(true); frame.setVisible(true); wormStage.action(); } }