JAVA贪吃蛇项目

以下学习的是B站上的视频

贪吃蛇:1小时Java开发贪吃蛇游戏 [编号:J301]

视频网址:
https://www.bilibili.com/video/BV1AJ411A7rP?p=1&vd_source=ef168c2d76bcab95329424c907fc8f6f

源码及其图片网址:
https://gitee.com/bigmmm/maishu_java/tree/master

基于这个,增加了碰墙会结束游戏,以及额外多了毒物,吃了会减少一个长度,吃得食物越多,跑得速度会越快哦

import javax.swing.JFrame;  //导入JFrame类。

public class Msnake{   //定义了一个名为Msnake的公共类。
    public static void main(String[] args){  //定义了一个名为main的公共静态方法,程序从这里开始执行。
        // 画出白色窗口


        JFrame frame = new JFrame(); //创建一个JFrame对象实例。
        frame.setBounds(10, 10, 900, 720);  //设置JFrame对象的位置和大小,分别为x轴位置、y轴位置、宽度和高度。
        frame.setResizable(false); //设置JFrame对象的大小是否可调整。
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //设置JFrame对象的默认关闭操作。
        //JFrame.EXIT_ON_CLOSE 是一个静态常量,表示关闭 JFrame 窗口时默认的操作,即退出程序。
        //当用户点击关闭窗口按钮时,程序会自动调用 System.exit(0) 方法,使程序退出。
        frame.add(new Mpanel()); //将一个新的Mpanel面板添加到frame中,使得Mpanel面板可以显示在frame窗口中。
        frame.setVisible(true);  //将窗口设置为可见状态。JFrame对象会自动调用Mpanel的paintComponent方法来绘制面板。
        //实参为系统自动生成的Graphics对象,用于绘制图形。
    }
}
import java.awt.Color; //导入java.awt包中的Color类,用于设置颜色。
import java.awt.Font;  //导入了Java的 awt 库中的 Font 类。Font 类表示用于绘制文本的字体。
import java.awt.Graphics; //导入java.awt包中的Graphics类,用于绘制图形。
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;

// KeyEvent 类表示键盘事件,它包含有关键盘事件的详细信息,例如按下的键和释放的键。
// 通过使用 KeyEvent 类,可以在Java应用程序中处理键盘事件,例如监听用户按下或释放特定键。
// KeyListener 接口是一个监听器接口,用于处理键盘事件。通过实现 KeyListener 接口并重写其方法,可以在Java应用程序中处理键盘事件。
// 在实现 KeyListener 接口的类中,可以使用 KeyEvent 类的方法来获取有关键盘事件的详细信息,并执行相应的操作。
import javax.swing.ImageIcon; //导入javax.swing包中的ImageIcon类,用于加载图片。
import javax.swing.JPanel; //导入javax.swing包中的JPanel类,用于创建面板。
import javax.swing.Timer; 

public class Mpanel extends JPanel implements KeyListener, ActionListener{ 
// 这段代码定义了一个名为 Mpanel 的类,该类继承了 JPanel 类并实现了 KeyListener 接口。
// 继承 JPanel 类意味着 Mpanel 类可以像 JPanel 一样用于创建绘制图形的面板。
// 而实现 KeyListener 接口意味着 Mpanel 类可以监听并处理键盘事件。
// // 通过在 Mpanel 类中重写 KeyListener 接口中的方法,例如 keyPressed()、
// keyReleased() 和 keyTyped(),
// 可以在用户按下、释放或键入键盘键时执行相应的操作。因此,
// Mpanel 类可以用于创建具有交互性的用户界面,通过监听键盘事件来响应用户的输入。
    
    ImageIcon title =  new ImageIcon("title.jpg"); //创建一个ImageIcon对象,用于加载名为"title.jpg"的图片。
    ImageIcon body =  new ImageIcon("body.png");
    ImageIcon up =  new ImageIcon("up.png");
    ImageIcon down =  new ImageIcon("down.png");
    ImageIcon left =  new ImageIcon("left.png");
    ImageIcon right =  new ImageIcon("right.png");
    ImageIcon food =  new ImageIcon("food.png");
    ImageIcon poison =  new ImageIcon("poison.png");
    int foodx; //食物
    int foody;
    int poisonx; //毒物
    int poisony;
    Random rand = new Random(); //Random 类是 Java 中的一个随机数生成器类,它可以生成伪随机数序列。
    int len = 3; //定义蛇的初始长度s
    int score = 0; //定义蛇的分数
    int[] snakex = new int[750];  //用来存放蛇头及其蛇身的位置
    int[] snakey = new int[750]; 
    String dir = "R"; //蛇的初始方向,有:R , L , U ,D
    boolean isStarted = false;  //判断游戏是否开启
    boolean isFailed = false; //判断游戏是否结束
    Timer timer = new Timer(100, this);
   //  这行代码创建了一个名为 timer 的 Timer 对象,它在每 100 毫秒触发一次。
   //  Timer 构造函数的第一个参数表示计时器的间隔时间,以毫秒为单位。在这里,间隔时间被设置为 100 毫秒。
   //  构造函数的第二个参数是一个 ActionListener 对象,用于指定计时器触发时要执行的操作。
   // 这里使用 this 关键字作为第二个参数,
   // 表示该计时器将触发当前对象(通常是实现了 ActionListener 接口的对象)中的 actionPerformed() 方法。
   //  因此,当 timer 被启动时,每隔 100 毫秒就会触发一次 actionPerformed() 方法。
   // 在该方法中,可以编写需要周期性执行的代码。
   
    public Mpanel(){ //Mpanel类的构造函数,用于创建Mpanel对象。
        initSnake();  //初始化蛇
        this.setFocusable(true); //使当前组件可以获得焦点,即可以接收用户的输入事件。
        this.addKeyListener(this);//通过这种方式,程序就可以响应用户的键盘输入,实现一些交互功能。
        timer.start(); // 是一个方法调用,它用于启动一个计时器对象。
    }

    public void initSnake(){  //蛇的初始化
        len = 3;  //蛇的初始长度
        dir = "R"; 
        score = 0; 
        snakex[0] = 100;   //蛇头的位置
        snakey[0] = 100;

        snakex[1] = 75;   //蛇身的第一个位置
        snakey[1] = 100;

        snakex[2] = 50;   //蛇身的第二个位置
        snakey[2] = 100;
        
        foodx = 25 + 25 * rand.nextInt(34);//  rand.nextInt(34) 生成0-33之间的随机整数
        foody = 75 + 25 * rand.nextInt(24);

        poisonx = 25 + 25 * rand.nextInt(34);//  rand.nextInt(34) 生成0-33之间的随机整数
        poisony = 75 + 25 * rand.nextInt(24);

    }
    public void paintComponent(Graphics g){ // 重写JPanel类中的paintComponent方法,用于绘制面板。

         super.paintComponent(g); //调用JPanel类的paintComponent方法,清除面板并准备绘制新的内容。
         this.setBackground(Color.WHITE);//设置面板的背景颜色为绿色。
         title.paintIcon(this, g, 25, 11);//在面板上绘制名为"title.jpg"的图片,位置为(25,11)。
         //其中,this表示当前的Mpanel对象,为要绘制图标的组件。g表示系统自动生成的Graphics对象,(25, 11)表示图标的左上角在Mpanel中的坐标。
         g.fillRect(25, 75, 850, 600);//在Mpanel面板上绘制一个实心矩形,起始点坐标为(25, 75),宽度为850,高度为600。
         g.setColor(Color.ORANGE);
         g.setFont(new Font("arial", Font.BOLD, 15));
         g.drawString("Len:" + len, 750, 35); //显示蛇的长度
         g.drawString("Score:" + score, 750, 50); //显示蛇的分数
         if( dir == "R" ){  //控制蛇头方向
            right.paintIcon(this, g, snakex[0], snakey[0]);
         }else if( dir == "L" ){
            left.paintIcon(this, g, snakex[0], snakey[0]);
         }else if( dir == "U" ){
            up.paintIcon(this, g, snakex[0], snakey[0]);
         }else
            down.paintIcon(this, g, snakex[0], snakey[0]);
         //  body.paintIcon(this, g, 75, 100);
         //  body.paintIcon(this, g, 50, 100);

         for( int i = 1; i < len; i++){  //绘制蛇身
            body.paintIcon(this, g, snakex[i], snakey[i]);
         }
         
         food.paintIcon(this, g, foodx, foody);
         poison.paintIcon(this, g, poisonx, poisony);

         if(isStarted == false){  //如果游戏未开始
            g.setColor(Color.WHITE);//设置画笔的颜色为白色(Color.WHITE)。在绘制图形或文字时,使用该画笔绘制的图形或文字颜色就会变成白色。
            g.setFont(new Font("arial", Font.BOLD, 60));//设置字体的样式和大小。具体来说,它创建了一个名为 "arial"、加粗(Font.BOLD)且大小为 60 的字体,并将该字体设置为画笔 g 的当前字体。
            //这意味着在接下来的绘图操作中,使用该画笔绘制的文字将会采用这种字体的样式和大小。
            g.drawString("Press Space to Start", 200, 300); //在屏幕上显示一段文字,文字内容为“Press Space to Start”,并且该文字的起始位置在屏幕的 (200, 300) 坐标处。
         }

         if(isFailed)  //如果游戏失败
         {
            g.setColor(Color.RED);
            g.setFont(new Font("arial", Font.BOLD, 40));
            g.drawString("Failed: Press Space to Restart", 200, 300);
         }
     }

      @Override
      public void keyPressed(KeyEvent e) {
          int keyCode = e.getKeyCode();//KeyEvent 类的 getKeyCode() 方法返回被按下的键的键码。
          if(keyCode == KeyEvent.VK_SPACE){  //KeyEvent 类的 VK_SPACE 常量表示空格键的键码
                if(isFailed){
                    isFailed = false;
                    initSnake();  
                }else {
                  isStarted = !isStarted;
                }

                repaint();//按下空格键时重新绘制应用程序的界面。
          }else if(keyCode == KeyEvent.VK_LEFT){  //设置蛇移动方向
                dir = "L";
          }else if(keyCode == KeyEvent.VK_RIGHT){
                dir = "R";
          }else if(keyCode == KeyEvent.VK_UP){
                dir = "U";
          }else if(keyCode == KeyEvent.VK_DOWN){
                dir = "D";
          }
      }
      // @Override 是一个 Java 注解,用于指示被注解的方法是覆盖(重写)了父类中的同名方法。
      

      @Override
      public void keyReleased(KeyEvent e) {
       
      }

      @Override
      public void keyTyped(KeyEvent e) {
        
      }

      @Override
      public void actionPerformed(ActionEvent e) {
         if(isStarted && !isFailed){
            //控制蛇头移动
            if(dir == "R") {               
               if(snakex[0] == 850) { // 检查蛇头是否超出了面板的右边界。超出结束游戏
                  isFailed = true; 
               }else{
                  for(int i = len - 1; i > 0 ; i--){ //将蛇的身体向前移动一格。
                     snakex[i] = snakex[i - 1];
                     snakey[i] = snakey[i - 1];
                  }
                  snakex[0] = snakex[0] + 25;
               }
            }else if(dir == "L") {
               if(snakex[0] == 25){
                  isFailed = true; 
               }else{
                  for(int i = len - 1; i > 0 ; i--){ //将蛇的身体向前移动一格。
                     snakex[i] = snakex[i - 1];
                     snakey[i] = snakey[i - 1];
                  }
                  snakex[0] = snakex[0] - 25;
               }
            }else if(dir == "U") {
               if(snakey[0] == 75){
                  isFailed = true; 
               }else{
                  for(int i = len - 1; i > 0 ; i--){ //将蛇的身体向前移动一格。
                     snakex[i] = snakex[i - 1];
                     snakey[i] = snakey[i - 1];
                  }
                  snakey[0] = snakey[0] - 25;
               }
            }else if(dir == "D") {  
               if(snakey[0] == 650){
                   isFailed = true;
               }else{
                  for(int i = len - 1; i > 0 ; i--){ //将蛇的身体向前移动一格。
                     snakex[i] = snakex[i - 1];
                     snakey[i] = snakey[i - 1];
                  }
                  snakey[0] = snakey[0] + 25;
               }
            } 
            if(snakex[0] == foodx && snakey[0] == foody){  //如果蛇吃了食物
               len++;
               score++;
               foodx = 25 + 25 * rand.nextInt(34);
               foody = 75 + 25 * rand.nextInt(24);
               timer.setDelay(timer.getDelay() - 10); //将计时器的间隔时间减少 10 毫秒。
            }
            if(snakex[0] ==  poisonx && snakey[0] ==  poisony){  //如果蛇吃了毒物
               len--;
               score--;
               poisonx = 25 + 25 * rand.nextInt(34);
               poisony = 75 + 25 * rand.nextInt(24);
               timer.setDelay(timer.getDelay() + 10); 
            }
            for(int i = 1; i < len; i++){
                if(snakex[i] == snakex[0] && snakey[i] == snakey[0]){
                     isFailed = true;
                }
            }
            if(len == 1){
                isFailed = true;
            }
            repaint(); //调用 repaint() 方法,以便在蛇的位置更新后重新绘制应用程序的界面。
         }
         timer.start(); 
         //调用 timer.start() 方法,以便在处理完当前事件后继续触发计时器对象。
         //此时,计时器将按照指定的时间间隔再次触发 actionPerformed() 方法,从而实现连续的蛇移动效果。
      }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值