贪吃蛇代码

本文介绍了如何使用Java创建一个简单的蛇形游戏,包括创建SnakeJPanel,定义游戏状态、速度、食物生成以及使用键盘事件控制蛇的移动。玩家可以设置蛇的移动速度,游戏通过JFrame启动,具有基本的得分系统和画面绘制功能。
摘要由CSDN通过智能技术生成

创建一个名为images的文件夹用来存放游戏相关图片

构造底层代码

  1. package snake;
  2.  
  3. import java.awt.Color;
  4. import java.awt.EventQueue;
  5. import java.awt.Font;
  6. import java.awt.Frame;
  7. import java.awt.Graphics;
  8. import java.awt.Image;
  9. import java.util.ArrayList;
  10. import java.util.List;
  11. import java.util.Random;
  12.  
  13. import javax.swing.ImageIcon;
  14. import javax.swing.JFrame;
  15. import javax.swing.JOptionPane;
  16. import javax.swing.JPanel;
  17. import javax.swing.Timer;
  18. import javax.swing.border.EmptyBorder;
  19.  
  20.  
  21. import java.awt.event.ActionEvent;
  22. import java.awt.event.ActionListener;
  23. import java.awt.event.KeyAdapter;
  24. import java.awt.event.KeyEvent;
  25.  
  26. public class SnakeJPanel extends JPanel implements ActionListener{
  27.     
  28.     private boolean start;//当前游戏状态
  29.     
  30.     private int speed;//速度
  31.     
  32.     private boolean exist;//当前是否存在食物
  33.     
  34.     private int foodType;//食物种类
  35.     
  36.     private int x;//豆子的横坐标
  37.     private int y;//豆子的纵坐标
  38.     
  39.     private ArrayList<int[]> localList;//蛇
  40.     
  41.     
  42.     public String direction;//方向
  43.     
  44.     private String direction2;//引导方向
  45.     
  46.     public boolean flag;
  47.     
  48.     Random rand = new Random();
  49.  
  50.     private ImageIcon up;
  51.  
  52.     private ImageIcon down;
  53.  
  54.     private ImageIcon right;
  55.  
  56.     private ImageIcon left;
  57.  
  58.     private ImageIcon body;
  59.  
  60.     private ImageIcon food;
  61.  
  62.     private ImageIcon title;
  63.     
  64.     Timer time;
  65.     
  66.     private int score;//当前得分情况
  67.     
  68.     private int num;//吃到的食物个数
  69.     
  70. //    private Image offScreenImage;  //图形缓存
  71.     
  72.     
  73.     //图片绘制
  74.     @Override
  75.     public void paint(Graphics g) {
  76.         
  77.         direction = direction2;
  78.         
  79.         g.setColor(Color.WHITE);
  80.         g.fillRect(0, 0, 900, 700);
  81.         
  82.         //绘制游戏框
  83.         //标题框
  84. //        g.drawRect(25, 30, 800, 75);
  85.         title.paintIcon(this, g, 25, 10);
  86.         
  87.         //内容框
  88.         g.setColor(Color.black);
  89.         g.fillRect(25, 75, 850, 600);
  90.         
  91.         //绘制食物的坐标位置
  92.         if(!exist) {//如果当前不存在豆子,随机绘制一个豆子    
  93.             if(num % 5 == 0) {
  94.                 foodType = 1;
  95.             }else {
  96.                 foodType = 0;
  97.             }
  98.             boolean isProduce = true;
  99.             while(isProduce) {
  100.                 isProduce = false;
  101.                 x = rand.nextInt(33) * 25 + 25;        
  102.                 y = rand.nextInt(23) * 25 + 75;            
  103.                 for (int[] arr:localList) {
  104.                     if(x == arr[0] && y == arr[1]) {    
  105.                         isProduce = true;
  106.                         break;    
  107.                     }
  108.                 }
  109.                 
  110.             }            
  111.             System.out.println(x + "---" + y);
  112.         }
  113.         
  114.          if(eat()) {
  115.             exist = false;
  116.          }else {
  117.             exist = true;
  118.          }
  119.          
  120.          
  121.         if(foodType == 0) {
  122.             //绘制食物
  123.             g.setColor(Color.blue);
  124. //            g.fillRect(x, y, 25, 25);
  125.             g.drawImage(food.getImage(),x, y, 25, 25,null);
  126.         }else {
  127.             //绘制食物
  128.             g.setColor(Color.WHITE);
  129.             g.fillRect(x, y, 25, 25);
  130. //            g.drawImage(food.getImage(),x, y, 25, 25,null);
  131.         }
  132.     
  133.             
  134.         //绘制头
  135.         g.setColor(Color.red);
  136. //        g.fillRect(localList.get(0)[0], localList.get(0)[1], 25, 25);    
  137.         ImageIcon head = null;
  138.         //判断当前方向
  139.         if(direction.equals("R")) {
  140.              head = right;
  141.         }else if(direction.equals("L")) {
  142.              head = left;
  143.         }else if(direction.equals("U")) {
  144.              head = up;
  145.         }else if(direction.equals("D")) {
  146.              head = down;
  147.         }        
  148. //        g.drawImage(head.getImage(), localList.get(0)[0], localList.get(0)[1], 25, 25,null);
  149.         head.paintIcon(this, g,localList.get(0)[0], localList.get(0)[1]);
  150.         
  151.         //绘制身体
  152.         g.setColor(Color.white);
  153.         for (int i = 1; i < localList.size(); i++) {
  154. //            g.fillRect(localList.get(i)[0], localList.get(i)[1], 25, 25);
  155. //            g.drawImage(body.getImage(), localList.get(i)[0], localList.get(i)[1], 25, 25,null);
  156.             body.paintIcon(this, g, localList.get(i)[0], localList.get(i)[1]);
  157.         }
  158. //        g.fillRect(localList.get(1)[0], localList.get(1)[1], 25, 25);
  159. //        g.fillRect(localList.get(2)[0], localList.get(2)[1], 25, 25);
  160.             
  161.         
  162.         //绘制分数和长度
  163.         //长度
  164.         g.setColor(Color.GREEN);
  165.         g.setFont(new Font("宋体", Font.BOLD, 18));
  166.         g.drawString("长度:" + (localList.size() - 1), 25, 30);
  167.         
  168.         //分数
  169.         g.drawString("分数:" + score, 25, 48);
  170.         
  171.         if(!start) {//如果游戏未启动,结束移动和重绘
  172.             g.setColor(Color.white);
  173.             g.setFont(new Font("宋体", Font.BOLD, 30));
  174.             g.drawString("暂停/开始(请按任意键开始,空格键暂停)", 150, 300);
  175.             time.stop();
  176.             
  177.         }else {
  178.             time.start();
  179.         }
  180.             
  181. //        speed();
  182.         //移动后进行下一次绘制        
  183. //      move();//移动
  184. //        repaint();//重新绘制        
  185.     }
  186.     
  187. //    //解决闪烁问题
  188. //    //如果为JFrame 为重量级  程序不会调用update()方法
  189. //    //如果为Frame 为轻量级  重写update()方法 做双缓冲
  190. //    //如果为JPanel 不会闪烁
  191. //      @Override
  192. //        public void update(Graphics g)
  193. //        {
  194. //            System.out.println("update");
  195. //               if(offScreenImage == null)
  196. //                  offScreenImage = this.createImage(900, 700);  //新建一个图像缓存空间,这里图像大小为800*600
  197. //                  Graphics gImage = offScreenImage.getGraphics();  //把它的画笔拿过来,给gImage保存着
  198. //                  paint(gImage);                                   //将要画的东西画到图像缓存空间去
  199. //                  g.drawImage(offScreenImage, 0, 0, null);         //然后一次性显示出来
  200. //        }
  201.     
  202.  
  203.     @Override
  204.     public void actionPerformed(ActionEvent e) {        
  205.         //移动后进行下一次绘制        
  206.         move();//移动
  207.         repaint();//重新绘制        
  208.         
  209.     }
  210.  
  211.     /**
  212.      * 绘制速度
  213.      */
  214. //    private void speed() {
  215. //        try {//按一定速度进行移动
  216. //            Thread.sleep(speed);//控制移动速度
  217. //        } catch (InterruptedException e) {
  218. //            // TODO 自动生成的 catch 块
  219. //            e.printStackTrace();
  220. //        }
  221. //    }
  222.  
  223.     /**
  224.      * 初始化图片
  225.      */
  226.     private void drawImage() {
  227.         up = new ImageIcon("images/up.png");
  228.         down = new ImageIcon("images/down.png");
  229.         right = new ImageIcon("images/right.png");
  230.         left = new ImageIcon("images/left.png");
  231.         body = new ImageIcon("images/body.png");
  232.         food = new ImageIcon("images/food.png");
  233.         title = new ImageIcon("images/title.jpg");
  234.     }
  235.     
  236.     private boolean eat() {
  237.         if(localList.get(0)[0] == x && localList.get(0)[1] == y) {//如果当前蛇头吃到了豆子
  238.             System.out.println("eat");
  239.             num++;
  240.             if(foodType == 0) {
  241.                 score += 10;
  242.             }else {
  243.                 score += (rand.nextInt(5) * 10 + 10);
  244.             }
  245.             int last = localList.size() - 1;//蛇尾            
  246.             //在蛇尾后面添加一节身体
  247.             localList.add(new int[] {localList.get(last)[0],localList.get(last)[1]});
  248.             return true;
  249.         }
  250.         return false;
  251.     }
  252.  
  253.     //移动方法
  254.     public void move() {
  255.         //判断是否游戏结束
  256.         if(isbody()) {
  257.             System.out.println("game over");
  258.             start = false;//结束游戏移动
  259.             JOptionPane.showMessageDialog(null,"游戏已结束!");
  260.             time.stop();
  261.             init();        
  262.         }
  263.             
  264.         if(flag && localList != null) {//如果长度不为空且游戏未结束                
  265.             int last = localList.size() - 1;//记录蛇尾
  266.             
  267.             for (int i = last; i > 0; i--) {//从蛇尾开始,每节身体移动到前一节身体的位置上
  268.                 localList.set(i,new int[] {localList.get(i - 1)[0],localList.get(i - 1)[1]});
  269.             }
  270.             
  271.             //记录头位置
  272.             int[] local = localList.get(0);
  273.             //判断当前方向,并进行模拟移动,判断是否与边界重合
  274.             if(direction.equals("R")) {
  275.                 if(local[0] >= 850) {
  276.                     local[0] = 25;
  277.                 }else {
  278.                     local[0] += 25;
  279.                 }
  280.                 
  281.             }else if(direction.equals("L")) {
  282.                 if(local[0] <= 25) {
  283.                     local[0] = 850;
  284.                 }else {
  285.                     local[0] -= 25;
  286.                 }
  287.                 
  288.             }else if(direction.equals("U")) {
  289.                 
  290.                 if(local[1] <= 75) {
  291.                     local[1] = 650;
  292.                 }else {
  293.                     local[1] -= 25;
  294.                 }
  295.                 
  296.             }else if(direction.equals("D")) {
  297.                 if(local[1] >= 650) {
  298.                     local[1] = 75;
  299.                 }else {
  300.                     local[1] += 25;
  301.                 }
  302.                 
  303.             }            
  304.                         
  305.             //更改头的位置
  306.             localList.set(0, local);        
  307.         }    
  308.     }
  309.     
  310.     //判断下一步是否为蛇身
  311.     private boolean isbody() {
  312.         // TODO 自动生成的方法存根
  313.         //记录头位置
  314.         int x = localList.get(0)[0];
  315.         int y = localList.get(0)[1];
  316.  
  317.         //判断当前方向,并进行模拟移动,判断是否与边界重合
  318.         if(direction.equals("R")) {
  319.             x += 25;
  320.         }else if(direction.equals("L")) {
  321.             x -= 25;
  322.         }else if(direction.equals("U")) {
  323.             y -= 25;
  324.         }else if(direction.equals("D")) {
  325.             y += 25;
  326.         }            
  327.         
  328.         for (int i = 1; i < localList.size(); i++) {
  329.             if(localList.get(i)[0] == x && localList.get(i)[1] == y) {
  330.                 return true;
  331.             }
  332.         }
  333.         return false;
  334.  
  335.     }
  336.     
  337. //    //判断下一步是否为边界
  338. //    private boolean isborder() {
  339. //        // TODO 自动生成的方法存根
  340. //        //记录头位置
  341. //        // TODO 自动生成的方法存根
  342. //        //记录头位置
  343. //        int x = localList.get(0)[0];
  344. //        int y = localList.get(0)[1];
  345. //
  346. //        //判断当前方向,并进行模拟移动,判断是否与边界重合
  347. //        if(direction.equals("R")) {
  348. //            x += 25;
  349. //        }else if(direction.equals("L")) {
  350. //            x -= 25;
  351. //        }else if(direction.equals("U")) {
  352. //            y -= 25;
  353. //        }else if(direction.equals("D")) {
  354. //            y += 25;
  355. //        }    
  356. //                
  357. //        if(x < 25 || x > (33 * 25 + 25)) {
  358. //            return true;//当x坐标超出边界,则返回true
  359. //        }
  360. //        if(y < 105 || y > (23 * 25 + 105)) {
  361. //            return true;//当y坐标超出边界,则返回true
  362. //        }
  363. //        return false;//蛇头移动后未超出边界,返回false
  364. //        
  365. //    }
  366.  
  367.     /**
  368.      * Create the frame.
  369.      */
  370.     public SnakeJPanel(int speed) {
  371.         
  372.         this.speed = speed; //初始化速度
  373.         
  374.         //初始化游戏面板的基本信息
  375.         this.setSize(900, 700);
  376.         this.setLocation(0, 30);
  377.         this.setFocusable(true);
  378.         
  379.         init();//初始化界面
  380.         drawImage();//绘制图片
  381.         moveByKey();//给界面添加一个键盘监听
  382.                 
  383.     }
  384.  
  385.     /*
  386.      * 键盘监听
  387.      * 通过键盘输入上下左右来控制当前蛇头移动的方向
  388.      * 先判断当前蛇头方向,再来改变引导方向
  389.      * 当进行绘制时再修改蛇的方向
  390.      * 保证不会因为在短时间内快速变换方向导致蛇头逆向转向
  391.      */
  392.     private void moveByKey() {
  393.         addKeyListener(new KeyAdapter() {
  394.             @Override
  395.             public void keyPressed(KeyEvent e) {
  396.                 int key = e.getKeyCode();
  397.                 //边界值判断
  398.                 switch(key) {
  399.                 case 65:
  400.                 case 37:{//向左走
  401.                     if(!direction.equals("R")) {
  402.                         direction2 = "L";
  403.                         
  404.                     }
  405.                     break;
  406.                 }                
  407.                 case 87:
  408.                 case 38:{//向上走
  409.                     if(!direction.equals("D")) {
  410.                         direction2 = "U";
  411.                     }                
  412.                     break;
  413.                 }                
  414.                 case 68:
  415.                 case 39:{//向右走
  416.                     if(!direction.equals("L")) {
  417.                         direction2 = "R";
  418.                     }
  419.                     break;
  420.                 }
  421.                 case 83:
  422.                 case 40:{//向下走
  423.                     if(!direction.equals("U")) {
  424.                         direction2 = "D";
  425.                     }                    
  426.                     break;
  427.                 }
  428.                 case KeyEvent.VK_SPACE:{//如果当前键盘输入为空格
  429.                     start = !start;//调整游戏状态
  430.                     System.out.println("暂停/开始");
  431.                     repaint();//重绘
  432.                 }
  433.                 }
  434.                 
  435.                 //任意键开始
  436.                 if(!start && key != KeyEvent.VK_SPACE) {//如果当前状态为暂停状态,且键盘输入不是空格
  437.                     start = true;
  438.                     repaint();//重绘
  439.                     
  440.                 }                
  441.             }
  442.         });
  443.     }
  444.  
  445.     /**
  446.      * 初始化游戏基本信息
  447.      */
  448.     private void init() {
  449.         start = false;
  450.  
  451.         exist = true;
  452.  
  453.         direction2 = "U";
  454.  
  455.         flag = true;
  456.  
  457.         localList = new ArrayList<int[]>();
  458.  
  459.         localList.add(0,new int[] {75,125});//蛇头
  460.         localList.add(1,new int[] {75,150});//蛇身1
  461.         localList.add(2,new int[] {75,175});//蛇身2
  462.  
  463.         //创建第一个食物的位置
  464.         //通过循环保证当前生成的食物不在身体所在的坐标上
  465.         boolean isProduce = true;
  466.         while(isProduce) {//循环生成食物坐标
  467.             isProduce = false;//结束本次循环
  468.             x = rand.nextInt(33) * 25 + 25;        
  469.             y = rand.nextInt(23) * 25 + 75;            
  470.             for (int[] arr:localList) {//循环遍历蛇头及蛇身的坐标
  471.                 if(x == arr[0] && y == arr[1]) {//如果食物坐标和蛇的某一节坐标重合
  472.                     isProduce = true;//跳转循环状态,继续下一次食物生成
  473.                     break;    
  474.                 }
  475.             }
  476.             //蛇身遍历完成,没有重合坐标,结束食物坐标生成
  477.                             
  478.         }
  479.  
  480.         time = new Timer(speed, this);
  481.         setLayout(null);
  482.  
  483.         score = 0;
  484.  
  485.         num = 0;
  486.         
  487.         foodType = 0;
  488.         
  489. //        repaint();
  490.         
  491.     }
  492.  
  493.  
  494. }

构造游戏启动类

  1. package snake;
  2.  
  3. import javax.swing.JFrame;
  4. import javax.swing.JOptionPane;
  5.  
  6. import snake.SnakeJPanel;
  7.  
  8. public class SnakeStart {
  9.     public static void main(String[] args) {
  10.         
  11.         int speed = 0;
  12.         String showInputDialog = null;//初始化时间
  13.         //得到速度
  14.         while(true) {
  15.             showInputDialog = JOptionPane.showInputDialog("蛇移动速度(1 - 5)","3");
  16.             
  17.             if(showInputDialog == null) {
  18.                 showInputDialog = "3";//默认速度
  19.                 break;
  20.             }
  21.             if(showInputDialog.length() > 1) {
  22.                 continue;
  23.             }
  24.             char[] a = showInputDialog.toCharArray();
  25.             if(a[0] >= '1' && a[0] <= '5') {
  26.                 break;
  27.             }      
  28.         }
  29.             
  30.         speed = Integer.parseInt(showInputDialog) * 50;
  31.         
  32.         
  33.         SnakeJPanel snakeJPanel = new SnakeJPanel(speed);
  34.         
  35.         //创建一个JFrame窗口,将游戏面板添加进行窗口中
  36.         JFrame jFrame = new JFrame();
  37.         //设置窗口的某些属性
  38.         jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  39.         jFrame.setSize(920, 750);
  40.         jFrame.add(snakeJPanel);
  41.         jFrame.setLocationRelativeTo(null);
  42.         jFrame.setVisible(true);
  43.     }
  44.  
  45. }

启动游戏,设置蛇的运行速度

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值