1.简介:
贪吃蛇是经典游戏,既简单又耐玩
2.玩法:
玩家通过键盘控制蛇在地图上寻找食物,吃下食物会使蛇变长,吃到一定数量的食物就会过关.
3.说明:
在游戏开发的过程中,只实现了地图的绘制,按键的控制,吃下食物会使蛇变长,边界碰撞问题等基本功能,有兴趣的同学请继续在此基础上开发.
4.贪吃蛇开发思路
1.首先自定定义窗体,在窗体中自定义添加面板Jpanel.
2.在面板中绘制游戏移动的地图、蛇头、蛇身等并处理按键监听和线程操作。
3.实现在面板中随机出现可以吃的食物 作为要是20的倍数
4..实现方块和可以吃的小块碰撞
5.将蛇的身体每一块定义为Vector,有每块对应一个对象
6.实现死亡判定
package day11.snake; /** * 创建每一个节点 * 节点:即可以是蛇头,也可以是蛇身 * @author redarmy_chen * */ public class Node { private int nodeX, nodeY; private int nodeDir; public Node(int nodeX, int nodeY, int nodeDir) { this.nodeX = nodeX; this.nodeY = nodeY; this.nodeDir = nodeDir; } public int getNodeX() { return nodeX; } public int getNodeY() { return nodeY; } public int getNodeDir() { return nodeDir; } public void setNodeX(int nodeX) { this.nodeX = nodeX; } public void setNodeY(int nodeY) { this.nodeY = nodeY; } public void setNodeDir(int nodeDir) { this.nodeDir = nodeDir; } }
7.具体类的说明:
1.游戏绘制面板的类(使用到了Node类)
package day11.snake; import java.awt.Color; import java.awt.Graphics; import java.awt.RenderingHints.Key; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.Iterator; import java.util.Random; import java.util.Vector; import java.util.concurrent.TimeUnit; import javax.swing.JPanel; import javax.swing.plaf.basic.BasicSplitPaneUI.KeyboardEndHandler; public class GameJPanel extends JPanel implements KeyListener, Runnable { /** * */ private static final long serialVersionUID = 1L; //定义蛇头 private Node headNode; //游戏结束标志 private boolean temp = true; //蛇头的方向 private int headNodeDir = 2; //定义1,2,3,4,-1分别代表上、下、左、右、停止 private static final int DIR_UP = 1; private static final int DIR_DOWN = 2; private static final int DIR_LEFT = 3; private static final int DIR_RIGHT = 4; private static final int DIR_STOP = -1; //产生随机数的对象 private Random random; // 声明食物 private Node eatNode; // 声明蛇身 private Vector<Node> nodeBody; public GameJPanel() { //创建蛇头 headNode = new Node(130, 210, headNodeDir); // 添加监听 this.addKeyListener(this); // 实例化随机数类对象 random = new Random(); // 随机产生坐标,并且产生食物 randomCoord(); //实例化蛇身集合 nodeBody = new Vector<Node>(); } public void randomCoord() { int col = random.nextInt(10);// 0-9 int eatNodeX = col * 20 + 50; int row = random.nextInt(15);// 0-14 int eatNodeY = row * 20 + 50; // 实例化 eatNode = new Node(eatNodeX, eatNodeY, DIR_STOP); } @Override public void paint(Graphics g) { super.paint(g); //设置颜色 g.setColor(Color.red); //绘制行 的直线 for (int row = 50; row <= 350; row += 20) { g.drawLine(50, row, 250, row); } //绘制列 的直线 for (int col = 50; col <= 250; col += 20) { g.drawLine(col, 50, col, 350); } // 绘制蛇头 g.setColor(new Color(0.5f, 0.6f, 0.7f)); g.fillRect(headNode.getNodeX(), headNode.getNodeY(), 20, 20); // 绘制食物 g.setColor(new Color(0.8f, 0.8f, 0.8f)); g.fillRect(eatNode.getNodeX(), eatNode.getNodeY(), 20, 20); // x轴 50-----230 //50 +180 70 90 110 130 150 170 190 210 230 0*20 9*20 // y轴 50 -330 // 50 70 90 110 130 150 170 190 210 230 250 270 290 310 0*20 14*20 // 330 // 绘制蛇身 g.setColor(new Color(0.3f, 0.8f, 0.3f)); Iterator<Node> it = nodeBody.iterator(); while (it.hasNext()) { Node body = it.next(); g.fillRect(body.getNodeX(), body.getNodeY(), 20, 20); } // 获取焦点 this.requestFocus(); } @Override public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); //根据按键改变蛇头方向 switch (key) { case KeyEvent.VK_UP: headNode.setNodeDir(DIR_UP); break; case KeyEvent.VK_DOWN: headNode.setNodeDir(DIR_DOWN); break; case KeyEvent.VK_LEFT: headNode.setNodeDir(DIR_LEFT); break; case KeyEvent.VK_RIGHT: headNode.setNodeDir(DIR_RIGHT); break; } } @Override public void keyReleased(KeyEvent e) { // TODO Auto-generated method stub } @Override public void keyTyped(KeyEvent e) { // TODO Auto-generated method stub } @Override public void run() { while (temp) { try { // 先判断再移动 temp = checkBounds();// 判断边界 // 判断碰撞 checkHit(); if (temp) { moveHeadNode();// 移动蛇头 moveNodeBody();//移动蛇身 } // 重新绘制 this.repaint(); Thread.sleep(300); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } //移动蛇身 private void moveNodeBody() { // 获取所有的蛇身 Iterator<Node> it = nodeBody.iterator(); // 获取蛇头的方向 int headDir = headNode.getNodeDir(); int temp;//记录移动的方向 while (it.hasNext()) { Node body = it.next();// 获取具体的蛇身 int tmpDir = body.getNodeDir();// 获取蛇身的方向 //根据移动的方向 来改变蛇身坐标 switch (tmpDir) { case DIR_UP: body.setNodeY(body.getNodeY() - 20); break; case DIR_DOWN: body.setNodeY(body.getNodeY() + 20); break; case DIR_LEFT: body.setNodeX(body.getNodeX() - 20); break; case DIR_RIGHT: body.setNodeX(body.getNodeX() + 20); break; } temp = tmpDir;// 记录蛇身(食物)的方向 tmpDir = headDir;// 把蛇头方向赋值给第一个蛇身(食物) body.setNodeDir(tmpDir);//让食物的方向与蛇头(第二个食物把第一个食物当作蛇头)方向一致 headDir = temp;//记录蛇身(食物)的方向 /** * 1.第一次吃食物的时候: * 1.这个食物的方向与 蛇头一致 * 2.第二次吃食物的时候 * 1.这个食物的方向与 第一个食物的方向一致(把第一个食物当成蛇头) * 同理3、4、5....n */ } } //碰撞检测 private void checkHit() { // 碰撞 Node node; //当蛇头与食物的坐标完全重合的时候 if (headNode.getNodeX() == eatNode.getNodeX() && headNode.getNodeY() == eatNode.getNodeY()) { // if else完成的是:找到最后一个食物 if (nodeBody.size() == 0) { node = headNode;// 如果没有食物,第一个食物的坐标与方向 应该根据蛇头设置 } else { node = nodeBody.lastElement();// 如果有食物,最后要吃的食物的坐标与方向 应该根集合众最后一个食物一致 } int dir = node.getNodeDir();// 得到最后一个食物的方向 switch (dir) { case DIR_UP: eatNode.setNodeX(node.getNodeX()); eatNode.setNodeY(node.getNodeY() + 20); break; case DIR_DOWN: eatNode.setNodeX(node.getNodeX()); eatNode.setNodeY(node.getNodeY() - 20); break; case DIR_LEFT: eatNode.setNodeX(node.getNodeX() + 20); eatNode.setNodeY(node.getNodeY()); break; case DIR_RIGHT: eatNode.setNodeX(node.getNodeX() - 20); eatNode.setNodeY(node.getNodeY()); break; } eatNode.setNodeDir(node.getNodeDir());// 要吃的食物一定要与集合最后一个食物的方向一致。 nodeBody.add(eatNode);// 保存原有的食物 randomCoord();//产生新的食物 } } /** * 判断蛇头是否超出边界 */ private boolean checkBounds() { boolean flag = true; // 首先判断边界是否到左边 if (headNode.getNodeX() <= 50) { // 再判断蛇头是否还向左移动,如果方向向左移动 则GameOver 否则话游戏继续 if (headNode.getNodeDir() == DIR_LEFT) { flag = false; } } // 原理同上 if (headNode.getNodeX() >= 230) { if (headNode.getNodeDir() == DIR_RIGHT) { flag = false; } } // 原理同上 if (headNode.getNodeY() <= 50) { if (headNode.getNodeDir() == DIR_UP) { flag = false; } } // 原理同上 if (headNode.getNodeY() >= 330) { if (headNode.getNodeDir() == DIR_DOWN) { flag = false; } } return flag; } /** * 移动蛇头方法 */ private void moveHeadNode() { int headNodeDir = headNode.getNodeDir(); //根据蛇头的方向 来改变蛇头的坐标 switch (headNodeDir) { case DIR_UP: headNode.setNodeY(headNode.getNodeY() - 20); break; case DIR_DOWN: headNode.setNodeY(headNode.getNodeY() + 20); break; case DIR_LEFT: headNode.setNodeX(headNode.getNodeX() - 20); break; case DIR_RIGHT: headNode.setNodeX(headNode.getNodeX() + 20); break; } } }
2.窗体类
package day11.snake; import java.awt.Container; import javax.swing.JFrame; public class SnakeJFrame extends JFrame{ public GameJPanel gameJPanel; public SnakeJFrame() { this.setTitle("贪吃蛇游戏"); this.setVisible(true); this.setBounds(300, 200, 330, 430); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //首先获取Container Container c = this.getContentPane(); gameJPanel = new GameJPanel(); //添加面板 c.add(gameJPanel); new Thread(gameJPanel).start();//启动线程 } }
3.测试类
package day11.snake; public class SnakeGame { public static void main(String[] args) { new SnakeJFrame(); } }
4.执行结果
运行状态图:
死亡状态图:
希望同学们能够继续改进,做出更好的贪吃蛇游戏.