【java】贪吃蛇小游戏

时间:2022-03-12 15:24:57

1.简介:

     贪吃蛇是经典游戏,既简单又耐玩

2.玩法:

  玩家通过键盘控制蛇在地图上寻找食物,吃下食物会使蛇变长,吃到一定数量的食物就会过关.

3.说明:

     在游戏开发的过程中,只实现了地图的绘制,按键的控制,吃下食物会使蛇变长,边界碰撞问题等基本功能,有兴趣的同学请继续在此基础上开发.

4.贪吃蛇开发思路

 1.首先自定定义窗体,在窗体中自定义添加面板Jpanel.
 2.在面板中绘制游戏移动的地图、蛇头、蛇身等并处理按键监听和线程操作。
 3.实现在面板中随机出现可以吃的食物 作为要是20的倍数
 4..实现方块和可以吃的小块碰撞
 5.将蛇的身体每一块定义为Vector,有每块对应一个对象

 6.实现死亡判定

[java] view plaincopyprint?
  1. package day11.snake;  
  2.   
  3. /** 
  4.  * 创建每一个节点 
  5.  * 节点:即可以是蛇头,也可以是蛇身 
  6.  * @author redarmy_chen 
  7.  * 
  8.  */  
  9. public class Node {  
  10.   
  11.  private int nodeX, nodeY;  
  12.   
  13.  private int nodeDir;  
  14.   
  15.  public Node(int nodeX, int nodeY, int nodeDir) {  
  16.   this.nodeX = nodeX;  
  17.   this.nodeY = nodeY;  
  18.   this.nodeDir = nodeDir;  
  19.  }  
  20.   
  21.  public int getNodeX() {  
  22.   return nodeX;  
  23.  }  
  24.   
  25.  public int getNodeY() {  
  26.   return nodeY;  
  27.  }  
  28.   
  29.  public int getNodeDir() {  
  30.   return nodeDir;  
  31.  }  
  32.   
  33.  public void setNodeX(int nodeX) {  
  34.   this.nodeX = nodeX;  
  35.  }  
  36.   
  37.  public void setNodeY(int nodeY) {  
  38.   this.nodeY = nodeY;  
  39.  }  
  40.   
  41.  public void setNodeDir(int nodeDir) {  
  42.   this.nodeDir = nodeDir;  
  43.  }  
  44. }  

7.具体类的说明:

  1.游戏绘制面板的类(使用到了Node类)

[java] view plaincopyprint?
  1. package day11.snake;  
  2.   
  3. import java.awt.Color;  
  4. import java.awt.Graphics;  
  5. import java.awt.RenderingHints.Key;  
  6. import java.awt.event.KeyEvent;  
  7. import java.awt.event.KeyListener;  
  8. import java.util.Iterator;  
  9. import java.util.Random;  
  10. import java.util.Vector;  
  11. import java.util.concurrent.TimeUnit;  
  12.   
  13. import javax.swing.JPanel;  
  14. import javax.swing.plaf.basic.BasicSplitPaneUI.KeyboardEndHandler;  
  15.   
  16. public class GameJPanel extends JPanel implements KeyListener, Runnable {  
  17.   
  18.     /** 
  19.      *  
  20.      */  
  21.     private static final long serialVersionUID = 1L;  
  22.   
  23.     //定义蛇头  
  24.     private Node headNode;  
  25.     //游戏结束标志  
  26.     private boolean temp = true;  
  27.     //蛇头的方向  
  28.     private int headNodeDir = 2;  
  29.   
  30.     //定义1,2,3,4,-1分别代表上、下、左、右、停止  
  31.     private static final int DIR_UP = 1;  
  32.     private static final int DIR_DOWN = 2;  
  33.     private static final int DIR_LEFT = 3;  
  34.     private static final int DIR_RIGHT = 4;  
  35.     private static final int DIR_STOP = -1;  
  36.   
  37.     //产生随机数的对象  
  38.     private Random random;  
  39.     // 声明食物  
  40.     private Node eatNode;  
  41.     // 声明蛇身  
  42.     private Vector<Node> nodeBody;  
  43.   
  44.     public GameJPanel() {  
  45.         //创建蛇头  
  46.         headNode = new Node(130210, headNodeDir);  
  47.         // 添加监听  
  48.         this.addKeyListener(this);  
  49.         // 实例化随机数类对象  
  50.         random = new Random();  
  51.         // 随机产生坐标,并且产生食物  
  52.         randomCoord();  
  53.         //实例化蛇身集合  
  54.         nodeBody = new Vector<Node>();  
  55.     }  
  56.   
  57.     public void randomCoord() {  
  58.         int col = random.nextInt(10);// 0-9  
  59.         int eatNodeX = col * 20 + 50;  
  60.         int row = random.nextInt(15);// 0-14  
  61.         int eatNodeY = row * 20 + 50;  
  62.         // 实例化  
  63.         eatNode = new Node(eatNodeX, eatNodeY, DIR_STOP);  
  64.     }  
  65.   
  66.     @Override  
  67.     public void paint(Graphics g) {  
  68.         super.paint(g);  
  69.         //设置颜色  
  70.         g.setColor(Color.red);  
  71.         //绘制行 的直线  
  72.         for (int row = 50; row <= 350; row += 20) {  
  73.             g.drawLine(50, row, 250, row);  
  74.         }  
  75.         //绘制列 的直线  
  76.         for (int col = 50; col <= 250; col += 20) {  
  77.             g.drawLine(col, 50, col, 350);  
  78.         }  
  79.   
  80.         // 绘制蛇头  
  81.         g.setColor(new Color(0.5f, 0.6f, 0.7f));  
  82.         g.fillRect(headNode.getNodeX(), headNode.getNodeY(), 2020);  
  83.   
  84.         // 绘制食物  
  85.         g.setColor(new Color(0.8f, 0.8f, 0.8f));  
  86.   
  87.         g.fillRect(eatNode.getNodeX(), eatNode.getNodeY(), 2020);  
  88.   
  89.         // x轴 50-----230 //50 +180  70 90 110 130 150 170 190 210 230        0*20 9*20  
  90.         // y轴 50 -330 // 50 70 90 110 130 150 170 190 210 230 250 270 290 310  0*20 14*20  
  91.         // 330  
  92.   
  93.         // 绘制蛇身  
  94.         g.setColor(new Color(0.3f, 0.8f, 0.3f));  
  95.         Iterator<Node> it = nodeBody.iterator();  
  96.   
  97.         while (it.hasNext()) {  
  98.             Node body = it.next();  
  99.             g.fillRect(body.getNodeX(), body.getNodeY(), 2020);  
  100.         }  
  101.         // 获取焦点  
  102.         this.requestFocus();  
  103.     }  
  104.   
  105.     @Override  
  106.     public void keyPressed(KeyEvent e) {  
  107.         int key = e.getKeyCode();  
  108.         //根据按键改变蛇头方向  
  109.         switch (key) {  
  110.         case KeyEvent.VK_UP:  
  111.             headNode.setNodeDir(DIR_UP);  
  112.             break;  
  113.         case KeyEvent.VK_DOWN:  
  114.             headNode.setNodeDir(DIR_DOWN);  
  115.             break;  
  116.         case KeyEvent.VK_LEFT:  
  117.             headNode.setNodeDir(DIR_LEFT);  
  118.             break;  
  119.         case KeyEvent.VK_RIGHT:  
  120.             headNode.setNodeDir(DIR_RIGHT);  
  121.             break;  
  122.         }  
  123.     }  
  124.   
  125.     @Override  
  126.     public void keyReleased(KeyEvent e) {  
  127.         // TODO Auto-generated method stub  
  128.   
  129.     }  
  130.   
  131.     @Override  
  132.     public void keyTyped(KeyEvent e) {  
  133.         // TODO Auto-generated method stub  
  134.   
  135.     }  
  136.   
  137.     @Override  
  138.     public void run() {  
  139.           
  140.         while (temp) {  
  141.             try {  
  142.                 // 先判断再移动  
  143.                 temp = checkBounds();// 判断边界  
  144.                 // 判断碰撞  
  145.                 checkHit();  
  146.                 if (temp) {  
  147.                     moveHeadNode();// 移动蛇头  
  148.                     moveNodeBody();//移动蛇身  
  149.                 }  
  150.                 // 重新绘制  
  151.                 this.repaint();  
  152.                 Thread.sleep(300);  
  153.   
  154.             } catch (InterruptedException e) {  
  155.                 // TODO Auto-generated catch block  
  156.                 e.printStackTrace();  
  157.             }  
  158.         }  
  159.   
  160.     }  
  161.   
  162.     //移动蛇身  
  163.     private void moveNodeBody() {  
  164.         // 获取所有的蛇身  
  165.         Iterator<Node> it = nodeBody.iterator();  
  166.         // 获取蛇头的方向  
  167.         int headDir = headNode.getNodeDir();  
  168.   
  169.         int temp;//记录移动的方向  
  170.           
  171.         while (it.hasNext()) {  
  172.             Node body = it.next();// 获取具体的蛇身  
  173.   
  174.             int tmpDir = body.getNodeDir();// 获取蛇身的方向   
  175.   
  176.             //根据移动的方向 来改变蛇身坐标  
  177.             switch (tmpDir) {  
  178.             case DIR_UP:  
  179.                 body.setNodeY(body.getNodeY() - 20);  
  180.                 break;  
  181.             case DIR_DOWN:  
  182.                 body.setNodeY(body.getNodeY() + 20);  
  183.                 break;  
  184.             case DIR_LEFT:  
  185.                 body.setNodeX(body.getNodeX() - 20);  
  186.                 break;  
  187.             case DIR_RIGHT:  
  188.                 body.setNodeX(body.getNodeX() + 20);  
  189.                 break;  
  190.             }  
  191.   
  192.             temp = tmpDir;// 记录蛇身(食物)的方向  
  193.   
  194.             tmpDir = headDir;// 把蛇头方向赋值给第一个蛇身(食物)  
  195.   
  196.             body.setNodeDir(tmpDir);//让食物的方向与蛇头(第二个食物把第一个食物当作蛇头)方向一致  
  197.   
  198.             headDir = temp;//记录蛇身(食物)的方向  
  199.               
  200.             /** 
  201.              * 1.第一次吃食物的时候: 
  202.              *     1.这个食物的方向与 蛇头一致 
  203.              * 2.第二次吃食物的时候 
  204.              *     1.这个食物的方向与 第一个食物的方向一致(把第一个食物当成蛇头) 
  205.              * 同理3、4、5....n 
  206.              */  
  207.   
  208.         }  
  209.   
  210.     }  
  211.   
  212.     //碰撞检测  
  213.     private void checkHit() {  
  214.         // 碰撞  
  215.         Node node;  
  216.         //当蛇头与食物的坐标完全重合的时候  
  217.         if (headNode.getNodeX() == eatNode.getNodeX()  
  218.                 && headNode.getNodeY() == eatNode.getNodeY()) {  
  219.             // if else完成的是:找到最后一个食物  
  220.             if (nodeBody.size() == 0) {  
  221.                 node = headNode;// 如果没有食物,第一个食物的坐标与方向 应该根据蛇头设置  
  222.             } else {  
  223.                 node = nodeBody.lastElement();// 如果有食物,最后要吃的食物的坐标与方向 应该根集合众最后一个食物一致  
  224.             }  
  225.   
  226.             int dir = node.getNodeDir();// 得到最后一个食物的方向  
  227.             switch (dir) {  
  228.             case DIR_UP:  
  229.                 eatNode.setNodeX(node.getNodeX());  
  230.                 eatNode.setNodeY(node.getNodeY() + 20);  
  231.                 break;  
  232.             case DIR_DOWN:  
  233.                 eatNode.setNodeX(node.getNodeX());  
  234.                 eatNode.setNodeY(node.getNodeY() - 20);  
  235.                 break;  
  236.             case DIR_LEFT:  
  237.                 eatNode.setNodeX(node.getNodeX() + 20);  
  238.                 eatNode.setNodeY(node.getNodeY());  
  239.                 break;  
  240.             case DIR_RIGHT:  
  241.                 eatNode.setNodeX(node.getNodeX() - 20);  
  242.                 eatNode.setNodeY(node.getNodeY());  
  243.                 break;  
  244.             }  
  245.   
  246.             eatNode.setNodeDir(node.getNodeDir());// 要吃的食物一定要与集合最后一个食物的方向一致。  
  247.   
  248.             nodeBody.add(eatNode);// 保存原有的食物  
  249.   
  250.             randomCoord();//产生新的食物  
  251.   
  252.         }  
  253.   
  254.     }  
  255.   
  256.     /** 
  257.      * 判断蛇头是否超出边界 
  258.      */  
  259.     private boolean checkBounds() {  
  260.         boolean flag = true;  
  261.         // 首先判断边界是否到左边  
  262.         if (headNode.getNodeX() <= 50) {  
  263.             // 再判断蛇头是否还向左移动,如果方向向左移动 则GameOver 否则话游戏继续  
  264.             if (headNode.getNodeDir() == DIR_LEFT) {  
  265.                 flag = false;  
  266.             }  
  267.         }  
  268.         // 原理同上  
  269.         if (headNode.getNodeX() >= 230) {  
  270.             if (headNode.getNodeDir() == DIR_RIGHT) {  
  271.                 flag = false;  
  272.             }  
  273.         }  
  274.         // 原理同上  
  275.         if (headNode.getNodeY() <= 50) {  
  276.             if (headNode.getNodeDir() == DIR_UP) {  
  277.                 flag = false;  
  278.             }  
  279.         }  
  280.         // 原理同上  
  281.         if (headNode.getNodeY() >= 330) {  
  282.             if (headNode.getNodeDir() == DIR_DOWN) {  
  283.                 flag = false;  
  284.             }  
  285.         }  
  286.         return flag;  
  287.   
  288.     }  
  289.   
  290.     /** 
  291.      * 移动蛇头方法 
  292.      */  
  293.     private void moveHeadNode() {  
  294.         int headNodeDir = headNode.getNodeDir();  
  295.         //根据蛇头的方向 来改变蛇头的坐标  
  296.         switch (headNodeDir) {  
  297.         case DIR_UP:  
  298.             headNode.setNodeY(headNode.getNodeY() - 20);  
  299.             break;  
  300.         case DIR_DOWN:  
  301.             headNode.setNodeY(headNode.getNodeY() + 20);  
  302.             break;  
  303.         case DIR_LEFT:  
  304.             headNode.setNodeX(headNode.getNodeX() - 20);  
  305.             break;  
  306.         case DIR_RIGHT:  
  307.             headNode.setNodeX(headNode.getNodeX() + 20);  
  308.             break;  
  309.         }  
  310.   
  311.     }  
  312.   
  313. }  

2.窗体类

[java] view plaincopyprint?
  1. package day11.snake;  
  2.   
  3. import java.awt.Container;  
  4.   
  5. import javax.swing.JFrame;  
  6.   
  7. public class SnakeJFrame extends JFrame{  
  8.   
  9.     public GameJPanel gameJPanel;  
  10.       
  11.       
  12.     public SnakeJFrame() {  
  13.         this.setTitle("贪吃蛇游戏");  
  14.         this.setVisible(true);  
  15.         this.setBounds(300200330430);  
  16.         this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
  17.           
  18.         //首先获取Container  
  19.         Container c = this.getContentPane();  
  20.         gameJPanel = new GameJPanel();  
  21.           
  22.         //添加面板  
  23.         c.add(gameJPanel);  
  24.           
  25.         new Thread(gameJPanel).start();//启动线程  
  26.     }  
  27. }  

3.测试类

[java] view plaincopyprint?
  1. package day11.snake;  
  2.   
  3. public class SnakeGame  {  
  4.       
  5.       
  6.     public static void main(String[] args) {  
  7.         new SnakeJFrame();  
  8.     }  
  9.   
  10. }  

4.执行结果

       运行状态图:

       【java】贪吃蛇小游戏

      死亡状态图:

     【java】贪吃蛇小游戏


文章转载出处http://blog.csdn.net/redarmy_chen/article/details/11794145