• 用java写一个贪吃蛇小游戏(源码在最后)


    一、引入

    涉及技能:

    1. 循环、分支
    2. 方法的抽取
    3. 数组的使用
    4. 面向对象
    5. 继承,子类方法的重写
    6. 接口,接口的实现
    7. GUI(图像化界面编程)

    GUI中的组件:
    7.1 窗口
    7.2 弹窗
    7.3 面板
    7.4 文本框
    7.5 列表框
    7.6 按钮
    7.7 图片
    7.8 交互的事件:监听事件(鼠标事件,键盘事件)

    GUI技术,不流行了!!!界面太简单粗糙!!

    已经被淘汰了,为什么还学?

    1. 提起兴趣
    2. 分层思想
    3. 锻炼监听器的思想
    4. 举一反三(蛇的图片换成其他图片,食物的图片换成其他图片)
    5. 工作中用到

    注意:
    学的是 思想!!!

    二、原理图

    小蛇素材图像素为25*25,因此在对应xy轴上的数值也以25为步长。
    在这里插入图片描述

    三、进入正题

    1.打开IDEA工具,新建一个模块module。
    在这里插入图片描述
    2.选择java,点next。
    在这里插入图片描述
    3.取一个名字叫TestSnake,然后点击finish。
    在这里插入图片描述
    4.打开新建好的TestSnake,在src下新建一个文件夹,取名为images。
    在这里插入图片描述
    在这里插入图片描述
    5.将所有的素材图片复制到images文件夹下。
    在这里插入图片描述
    在这里插入图片描述

    四、将图片加载到程序中

    1.在src下再新建一个文件夹com.game,在这个文件夹下新建一个类Images,用于获取图片。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    2.打开Images类,将以下代码写入,封装图片,后续使用时只要类名+图片即可。

    import javax.swing.*;
    import java.net.URL;
    
    /*用来获取游戏中所有涉及的图片*/
    public class Images {
    /*面向对象思想:将图片进行封装,封装为一个对象,在程序中通过操纵这个对象来操纵图片*/
    
        /*将图片的路径封装为一个对象:*/
    //    class获取字节码
    //    getResource获取图片路径
    //    在菜单Build下选中第二个Build Module,重写构建一下,生成对应的字节码信息
    //    在out文件夹下找图片路径
    //    '/'指代相对路径,相对file:/C:/Users/ASUS/Desktop/贪吃蛇小游戏/out/production/TestSnake/而言
        public static URL bodyURL=Images.class.getResource("/images/body.png");
    
        /*将图片封装为程序中一个对象:*/
    //    ImageIcon构造器,可以直接把url传进去
        public static ImageIcon bodyImg=new ImageIcon(bodyURL);
    
        /*同理,将剩下的图片都封装:*/
        public static URL downURL=Images.class.getResource("/images/down.png");
        public static ImageIcon downImg=new ImageIcon(downURL);
    
        public static URL foodURL=Images.class.getResource("/images/food.png");
        public static ImageIcon foodImg=new ImageIcon(foodURL);
    
        public static URL headerURL=Images.class.getResource("/images/header.png");
        public static ImageIcon headerImg=new ImageIcon(headerURL);
    
        public static URL leftURL=Images.class.getResource("/images/left.png");
        public static ImageIcon leftImg=new ImageIcon(leftURL);
    
        public static URL rightURL=Images.class.getResource("/images/right.png");
        public static ImageIcon rightImg=new ImageIcon(rightURL);
    
        public static URL upURL=Images.class.getResource("/images/up.png");
        public static ImageIcon upImg=new ImageIcon(upURL);
    
    
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    3.关于代码注释中的“在菜单Build下选中第二个Build Module,重写构建一下,生成对应的字节码信息”、“ 在out文件夹下找图片路径”的操作,具体步骤如下:
    在这里插入图片描述

    五、创建窗体

    1.在com.game文件夹下新建一个类,叫StartGame。
    在这里插入图片描述
    在这里插入图片描述
    2.将以下代码写入StartGame类中。

    package com.game;
    
    import javax.swing.*;
    import java.awt.*;
    
    public class StartGame {
        public static void main(String[] args) {
            /*1.创建一个窗体:*/
            JFrame jf=new JFrame();
            /*2.给窗体设置一个标题:*/
            jf.setTitle("贪吃蛇小游戏 by:cym");
            /*3.设置窗体弹出的坐标,对应窗体的宽和高:*/
    //        获取屏幕的宽、高
            int width = Toolkit.getDefaultToolkit().getScreenSize().width;
            int height = Toolkit.getDefaultToolkit().getScreenSize().height;
            jf.setBounds((width-800)/2,(height-800)/2,800,800);
            /*4.设置窗体大小不可调:*/
            jf.setResizable(false);
            /*5.关闭窗口的同时,程序随之关闭:*/
            jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    
            /*默认情况下窗体隐藏,需要进行显现(最好放在最后):*/
            jf.setVisible(true);
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    3.计算窗体在屏幕居中的方法如下:
    在这里插入图片描述

    六、创建面板

    1.新建一个类GamePanel。
    在这里插入图片描述
    在这里插入图片描述
    2.将以下代码写入GamePanel类中。

    package com.game;
    
    import javax.swing.*;
    import java.awt.*;
    
    /*面板*/
    //继承JPanel才具备面板的功能,才成为一个面板
    public class GamePanel extends JPanel {
        /*此方法特殊,就相当于图形版的main方法,自动调用*/
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            /*1.填充背景颜色:*/
    //        颜色由rgb(red green blue)组成
    //        可通过点击左边行号旁的色块进行颜色修改
            this.setBackground(new Color(243, 239, 190, 255));
    
            /*2.画头部的图片header.png:*/
    //        Images.headerImg:调用图片类中的header.png图片
    //        paintIcon()方法将图片在面板中绘制出来
    //        this:当前面板
    //        g:使用的画笔
    //        x、y:对应坐标轴
            Images.headerImg.paintIcon(this, g, 15, 10);
    
            /*3.画一个矩形:*/
    //        先调节画笔颜色:
            g.setColor(new Color(195, 205, 246));
    //        fillRect填充矩形
            g.fillRect(15, 70, 750, 670);
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    3.在StartGame类中添加第6 步创建面板,将面板添加到窗体中。

    package com.game;
    
    import javax.swing.*;
    import java.awt.*;
    /*窗体*/
    public class StartGame {
        public static void main(String[] args) {
            /*1.创建一个窗体:*/
            JFrame jf = new JFrame();
            /*2.给窗体设置一个标题:*/
            jf.setTitle("贪吃蛇小游戏 by:cym");
            /*3.设置窗体弹出的坐标,对应窗体的宽和高:*/
    //        获取屏幕的宽、高
            int width = Toolkit.getDefaultToolkit().getScreenSize().width;
            int height = Toolkit.getDefaultToolkit().getScreenSize().height;
            jf.setBounds((width - 800) / 2, (height - 800) / 2, 800, 800);
            /*4.设置窗体大小不可调:*/
            jf.setResizable(false);
            /*5.关闭窗口的同时,程序随之关闭:*/
            jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    
            /*6.创建面板:*/
            GamePanel gp=new GamePanel();
    //        将面板放入窗体中:
            jf.add(gp);
    
            /*默认情况下窗体隐藏,需要进行显现(最好放在最后):*/
            jf.setVisible(true);
    
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    七、画静态小蛇

    1.以这个图为例,做为一个默认小蛇,一个头,两节身子。
    在这里插入图片描述
    2.在面板类中的paintComponent()方法外部,写入以下代码。

    /*定义两个数组:
         * 一个数组,专门存储蛇的x轴坐标
         * 一个数组,专门存储蛇的y轴坐标
         * */
        int[] snakeX=new int[200];
        int[] snakeY=new int[200];
        /*定义蛇的长度:*/
        int length;
    
        /*自定义一个初始化方法,初始化小蛇的坐标:*/
        public void init(){
            /*初始化蛇的长度:*/
            length=3;
            /*初始化蛇头坐标:*/
            snakeX[0]=175;
            snakeY[0]=275;
            /*初始化第一节身子坐标:*/
            snakeX[1]=150;
            snakeY[1]=275;
            /*初始化第二节身子坐标:*/
            snakeX[2]=125;
            snakeY[2]=275;
    
        }
    
        /*构造器,调用一下小蛇默认方法init(),进行面板初始化的时候就默认了蛇的位置:*/
        public GamePanel(){
            init();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    3.在面板类中的paintComponent()方法内部,写第4步画小蛇,详见以下代码。

     /*4.画小蛇:*/
    //        画蛇头:
            Images.rightImg.paintIcon(this,g,snakeX[0],snakeY[0]);
            画第一节身子:
    //        Images.bodyImg.paintIcon(this,g,snakeX[1],snakeY[1]);
            画第二节身子:
    //        Images.bodyImg.paintIcon(this,g,snakeX[2],snakeY[2]);
    
    //        用循环来画蛇身子:
            for(int i=1;i<length;i++){
               Images.bodyImg.paintIcon(this,g,snakeX[i],snakeY[i]);
    
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    八、将蛇头按照行走方向改变

    1.定义蛇头的方向,代码如下。

    /*定义两个数组:
         * 一个数组,专门存储蛇的x轴坐标
         * 一个数组,专门存储蛇的y轴坐标
         * */
        int[] snakeX=new int[200];
        int[] snakeY=new int[200];
        /*定义蛇的长度:*/
        int length;
    
        /*定义蛇的行走方向:*/
        String direction;
    
        /*自定义一个初始化方法,初始化小蛇的坐标:*/
        public void init(){
            /*初始化蛇的长度:*/
            length=3;
            /*初始化蛇头坐标:*/
            snakeX[0]=175;
            snakeY[0]=275;
            /*初始化第一节身子坐标:*/
            snakeX[1]=150;
            snakeY[1]=275;
            /*初始化第二节身子坐标:*/
            snakeX[2]=125;
            snakeY[2]=275;
    
            /*初始化蛇头的方向为右:*/
            direction="R";//上U 下D 左L 右R
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    2.根据不同方向画蛇头,代码如下。

     /*4.画小蛇:*/
    //        画蛇头:
            if("R".equals(direction)){
               Images.rightImg.paintIcon(this,g,snakeX[0],snakeY[0]);
            }
            if("L".equals(direction)){
               Images.leftImg.paintIcon(this,g,snakeX[0],snakeY[0]);
            }
            if("U".equals(direction)){
               Images.upImg.paintIcon(this,g,snakeX[0],snakeY[0]);
            }
            if("D".equals(direction)){
               Images.downImg.paintIcon(this,g,snakeX[0],snakeY[0]);
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    九、加入监听,空格来控制游戏是否开始

    具体代码如下:

     /*游戏只有两个状态:开始、暂停*/
        boolean isStart=false;//默认游戏为暂停状态
    /*构造器,调用一下小蛇默认方法init(),进行面板初始化的时候就默认了蛇的位置:*/
        public GamePanel(){
            init();
    //        将焦点定位在当前操作的面板上
            this.setFocusable(true);
    //        加入监听:
    //        addKeyListener表示加入键盘监听
            this.addKeyListener(new KeyAdapter() {//涉及到适配器模式
    //            监听键盘按下操作
                @Override
                public void keyPressed(KeyEvent e) {
                    super.keyPressed(e);
                    int keyCode = e.getKeyCode();
    //                System.out.println(keyCode);//空格对应32
                    if (keyCode==32){
    //                    System.out.println("点击了空格");
                        isStart=!isStart;//点击了空格,将isStart变成相反的状态
                        repaint();//重绘,调用paintComponent方法
                    }
    
                }
            });
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
     /*5.如果游戏是暂停的,界面中间有一个提示语*/
            if(isStart==false){
                /*画一个文字:*/
    //            画笔设置颜色
                g.setColor(new Color(250, 3, 3));
    //            设置文字的字体、加粗、大小
                g.setFont(new Font("微软雅黑",Font.BOLD,40));
    //            画文字:
    //            drawString()方法,画字符串
    //            文字内容、xy轴坐标
                g.drawString("点击空格开始游戏",250,330);
                
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    十、小蛇向右动起来

    具体代码如下:

    /*加入一个定时器:*/
        Timer timer;
    /*构造器,调用一下小蛇默认方法init(),进行面板初始化的时候就默认了蛇的位置:*/
        public GamePanel(){
            init();
    //        将焦点定位在当前操作的面板上
            this.setFocusable(true);
    //        加入监听:
    //        addKeyListener表示加入键盘监听
            this.addKeyListener(new KeyAdapter() {//涉及到适配器模式
    //            监听键盘按下操作
                @Override
                public void keyPressed(KeyEvent e) {
                    super.keyPressed(e);
                    int keyCode = e.getKeyCode();
    //                System.out.println(keyCode);//空格对应32
                    if (keyCode==32){
    //                    System.out.println("点击了空格");
                        isStart=!isStart;//点击了空格,将isStart变成相反的状态
                        repaint();//重绘,调用paintComponent方法
                    }
    
                }
            });
    
            /*对定时器做初始化:*/
    //        延迟毫秒数、一个ActionListener类对象
            timer=new Timer(100, new ActionListener() {//创建ActionListener对象,一个匿名内部类
    //            ActionListener是 事件监听
    //            相当于每100ms监听你是否发生一个动作
    //            具体动作放入actionPerformed中
                @Override
                public void actionPerformed(ActionEvent e) {
                     if(isStart){//游戏开始状态下才动
    //                     由最后一节身子往前一节身子上动
                         for(int i=length-1;i>0;i--){
                             snakeX[i]=snakeX[i-1];
                             snakeY[i]=snakeY[i-1];
                         }
    //                     动头的位置
                         snakeX[0]+=25;
    //                     防止蛇超出边界:
                         if(snakeX[0]>750){
                            snakeX[0]=25;
                         }
                         repaint();//重绘,根据新的蛇头蛇身的位置画
                     }
                }
            });
    //        启动计时器
            timer.start();
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    十一、小蛇上下左右动起来

    代码如下:

     /*构造器,调用一下小蛇默认方法init(),进行面板初始化的时候就默认了蛇的位置:*/
        public GamePanel(){
            init();
    //        将焦点定位在当前操作的面板上
            this.setFocusable(true);
    //        加入监听:
    //        addKeyListener表示加入键盘监听
            this.addKeyListener(new KeyAdapter() {//涉及到适配器模式
    //            监听键盘按下操作
                @Override
                public void keyPressed(KeyEvent e) {
                    super.keyPressed(e);
                    int keyCode = e.getKeyCode();
    //                System.out.println(keyCode);//空格对应32
                    /*监听空格:*/
                    if (keyCode==KeyEvent.VK_SPACE){//将空格32封装起来
    //                    System.out.println("点击了空格");
                        isStart=!isStart;//点击了空格,将isStart变成相反的状态
                        repaint();//重绘,调用paintComponent方法
                    }
                    /*监听向上箭头:*/
                    if (keyCode==KeyEvent.VK_UP){
                        direction="U";
    
                    }
                    /*监听向下箭头:*/
                    if (keyCode==KeyEvent.VK_DOWN){
                        direction="D";
                    }
                    /*监听向左箭头:*/
                    if (keyCode==KeyEvent.VK_LEFT){
                        direction="L";
                    }
                    /*监听向右箭头:*/
                    if (keyCode==KeyEvent.VK_RIGHT){
                        direction="R";
                    }
    
                }
            });
    
            /*对定时器做初始化:*/
    //        延迟毫秒数、一个ActionListener类对象
            timer=new Timer(100, new ActionListener() {//创建ActionListener对象,一个匿名内部类
    //            ActionListener是 事件监听
    //            相当于每100ms监听你是否发生一个动作
    //            具体动作放入actionPerformed中
                @Override
                public void actionPerformed(ActionEvent e) {
                     if(isStart){//游戏开始状态下才动
    //                     由最后一节身子往前一节身子上动
                         for(int i=length-1;i>0;i--){
                             snakeX[i]=snakeX[i-1];
                             snakeY[i]=snakeY[i-1];
                         }
    //                     动头的位置
                         if("R".equals(direction)){
                             snakeX[0]+=25;
                         }
                         if("L".equals(direction)){
                             snakeX[0]-=25;
                         }
                         if("U".equals(direction)){
                             snakeY[0]-=25;
                         }
                         if("D".equals(direction)){
                             snakeY[0]+=25;
                         }
    
    //                     防止蛇超出边界:
                         if(snakeX[0]>745){
                            snakeX[0]=25;
                         }
                         if (snakeX[0]<25) {
                             snakeX[0]=745;
                         }
                         if(snakeY[0]<70){
                             snakeY[0]=700;
                         }
                         if(snakeY[0]>700){
                             snakeY[0]=70;
                         }
                         repaint();//重绘,根据新的蛇头蛇身的位置画
                     }
                }
            });
    //        启动计时器
            timer.start();
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    十二、画食物、吃食物

    1.画食物代码:

    /*定义食物的xy轴坐标*/
        int foodX,foodY;
     /*自定义一个初始化方法,初始化小蛇的坐标:*/
        public void init(){
            /*初始化蛇的长度:*/
            length=3;
            /*初始化蛇头坐标:*/
            snakeX[0]=175;
            snakeY[0]=275;
            /*初始化第一节身子坐标:*/
            snakeX[1]=150;
            snakeY[1]=275;
            /*初始化第二节身子坐标:*/
            snakeX[2]=125;
            snakeY[2]=275;
    
            /*初始化蛇头的方向为右:*/
            direction="R";//上U 下D 左L 右R
    
            /*初始化食物的坐标:*/
            foodX=300;
            foodY=200;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
     /*6.画食物:*/    Images.foodImg.paintIcon(this,g,foodX,foodY);
    
    
    • 1
    • 2

    2.吃食物代码:

     /*对定时器做初始化:*/
    //        延迟毫秒数、一个ActionListener类对象
            timer=new Timer(100, new ActionListener() {//创建ActionListener对象,一个匿名内部类
    //            ActionListener是 事件监听
    //            相当于每100ms监听你是否发生一个动作
    //            具体动作放入actionPerformed中
                @Override
                public void actionPerformed(ActionEvent e) {
                     if(isStart){//游戏开始状态下才动
    //                     由最后一节身子往前一节身子上动
                         for(int i=length-1;i>0;i--){
                             snakeX[i]=snakeX[i-1];
                             snakeY[i]=snakeY[i-1];
                         }
    //                     动头的位置
                         if("R".equals(direction)){
                             snakeX[0]+=25;
                         }
                         if("L".equals(direction)){
                             snakeX[0]-=25;
                         }
                         if("U".equals(direction)){
                             snakeY[0]-=25;
                         }
                         if("D".equals(direction)){
                             snakeY[0]+=25;
                         }
    
    //                     防止蛇超出边界:
                         if(snakeX[0]>725){
                            snakeX[0]=25;
                         }
                         if (snakeX[0]<25) {
                             snakeX[0]=725;
                         }
                         if(snakeY[0]<75){
                             snakeY[0]=700;
                         }
                         if(snakeY[0]>700){
                             snakeY[0]=75;
                         }
    
                         /*监测碰撞的动作,也就是吃食物的动作:*/
    //                     如果蛇头坐标与食物坐标一样时,即吃到食物
                         if (snakeX[0]==foodX&&snakeY[0]==foodY) {
    //                         蛇长度加一
                             length++;
    //                         食物坐标改变,随机生成坐标,随机数必须是25的倍数,x轴【25,725】,y轴【75,700】
    //                         方法一:
    //                         math.random()-->[0.0,1.0)
    //                         math.random()*29-->[0.0,29.0)
    //                         (int)(math.random()*29)-->[0,28]
    //                         (int)(math.random()*29)+1-->[1,29]
                             foodX=((int)(Math.random()*29)+1)*25;//[1,29]*25=[25,725]
    //                         方法二:
    //                         [75,700]-->[3,28]*25
    //                         [3,28]-->[0,25]+3
    //                         [0,25]
    //                         new Random().nextInt(26)-->[0,26)-->[0,25]
                             foodY=((new Random().nextInt(26))+3)*25;//[3,28]*25=[75,700]
                         }
    
                         repaint();//重绘,根据新的蛇头蛇身的位置画
                     }
                }
            });
    //        启动计时器
            timer.start();
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    十三、画积分

    代码如下:

     /*定义一个积分:*/
        int score;
         /*自定义一个初始化方法,初始化小蛇的坐标:*/
        public void init(){
            /*初始化蛇的长度:*/
            length=3;
            /*初始化蛇头坐标:*/
            snakeX[0]=175;
            snakeY[0]=275;
            /*初始化第一节身子坐标:*/
            snakeX[1]=150;
            snakeY[1]=275;
            /*初始化第二节身子坐标:*/
            snakeX[2]=125;
            snakeY[2]=275;
    
            /*初始化蛇头的方向为右:*/
            direction="R";//上U 下D 左L 右R
    
            /*初始化食物的坐标:*/
            foodX=300;
            foodY=200;
    
            /*初始化积分:*/
            score=0;
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
     /*监测碰撞的动作,也就是吃食物的动作:*/
    //                     如果蛇头坐标与食物坐标一样时,即吃到食物
                         if (snakeX[0]==foodX&&snakeY[0]==foodY) {
    //                         蛇长度加一
                             length++;
    //                         食物坐标改变,随机生成坐标,随机数必须是25的倍数,x轴【25,725】,y轴【75,700】
    //                         方法一:
    //                         math.random()-->[0.0,1.0)
    //                         math.random()*29-->[0.0,29.0)
    //                         (int)(math.random()*29)-->[0,28]
    //                         (int)(math.random()*29)+1-->[1,29]
                             foodX=((int)(Math.random()*29)+1)*25;//[1,29]*25=[25,725]
    //                         方法二:
    //                         [75,700]-->[3,28]*25
    //                         [3,28]-->[0,25]+3
    //                         [0,25]
    //                         new Random().nextInt(26)-->[0,26)-->[0,25]
                             foodY=((new Random().nextInt(26))+3)*25;//[3,28]*25=[75,700]
    
                             /*每吃到一次食物,积分加10*/
                             score+=10;
    
                         }
    
                         repaint();//重绘,根据新的蛇头蛇身的位置画
                     }
                }
            });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
      /*7.画积分(画文字):*/
            g.setColor(new Color(246, 245, 245));
            g.setFont(new Font("微软雅黑",Font.BOLD,20));
            g.drawString("积分:"+score,280,40);
    
    • 1
    • 2
    • 3
    • 4

    十四、死亡判定

            /*初始化积分:*/
            score=0;
    
    • 1
    • 2
     @Override
                public void keyPressed(KeyEvent e) {
                    super.keyPressed(e);
                    int keyCode = e.getKeyCode();
    //                System.out.println(keyCode);//空格对应32
                    /*监听空格:*/
                    if (keyCode==KeyEvent.VK_SPACE){//将空格32封装起来
                       if(isDie){
    //                    全部恢复到初始化状态
                           init();
                           isDie=false;
                       }else{
                           isStart=!isStart;
                           repaint();//重绘
                       }
    
                    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
     @Override
                public void actionPerformed(ActionEvent e) {
                     if(isStart&&isDie==false){//游戏开始状态、小蛇活着的状态下才动
    //                     由最后一节身子往前一节身子上动
                         for(int i=length-1;i>0;i--){
                             snakeX[i]=snakeX[i-1];
                             snakeY[i]=snakeY[i-1];
                         }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
      /*死亡判定:*/
                         for(int i=1;i<length;i++){
    //                         如果蛇头的坐标和身子的任意一节坐标一样
                             if (snakeX[0]==snakeX[i]&&snakeY[0]==snakeY[i]) {
    //                             判定为死亡状态
                                 isDie=true;
                             }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
     /*8.画死亡状态:*/
            if(isDie){
                g.setColor(new Color(246, 11, 11));
                g.setFont(new Font("微软雅黑",Font.BOLD,35));
                g.drawString("小蛇死亡!游戏停止,按下空格重新开始游戏",50,330);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    十五、游戏打包

    在对方电脑有jre的情况下,可以将程序打包发给对方。
    1.选择File菜单下的项目结构Project Structure
    在这里插入图片描述
    2.点击Artifacts,再点击左上角的“+”号,JAR包下选择from modules with dependencies从项目中将所有依赖选上
    在这里插入图片描述
    3.在Main Class中选择游戏进入的入口,即main方法所在的类。
    在这里插入图片描述
    4.此时已经生成了一个jar文件,点击Apply运行,再OK即可。
    在这里插入图片描述
    5.在菜单栏Build下选择Build Artifacts,再点击Build,就会生成jar包。
    在这里插入图片描述
    在这里插入图片描述
    6.生成好的jar包,可以在out文件夹下,找到刚生成好的jar包,右击选择Show inExplorer,就可以打开jar包所在位置
    在这里插入图片描述
    7.直接双击jar包,即可运行。
    在这里插入图片描述
    在这里插入图片描述

    源代码

    Images类:

    package com.game;
    
    import javax.swing.*;
    import java.net.URL;
    
    /*用来获取游戏中所有涉及的图片*/
    public class Images {
    /*面向对象思想:将图片进行封装,封装为一个对象,在程序中通过操纵这个对象来操纵图片*/
    
        /*将图片的路径封装为一个对象:*/
    //    class获取字节码
    //    getResource获取图片路径
    //    在菜单Build下选中第二个Build Module,重写构建一下,生成对应的字节码信息
    //    在out文件夹下找图片路径
    //    '/'指代相对路径,相对file:/C:/Users/ASUS/Desktop/贪吃蛇小游戏/out/production/TestSnake/而言
        public static URL bodyURL=Images.class.getResource("/images/body.png");
    
        /*将图片封装为程序中一个对象:*/
    //    ImageIcon构造器,可以直接把url传进去
        public static ImageIcon bodyImg=new ImageIcon(bodyURL);
    
        /*同理,将剩下的图片都封装:*/
        public static URL downURL=Images.class.getResource("/images/down.png");
        public static ImageIcon downImg=new ImageIcon(downURL);
    
        public static URL foodURL=Images.class.getResource("/images/food.png");
        public static ImageIcon foodImg=new ImageIcon(foodURL);
    
        public static URL headerURL=Images.class.getResource("/images/header.png");
        public static ImageIcon headerImg=new ImageIcon(headerURL);
    
        public static URL leftURL=Images.class.getResource("/images/left.png");
        public static ImageIcon leftImg=new ImageIcon(leftURL);
    
        public static URL rightURL=Images.class.getResource("/images/right.png");
        public static ImageIcon rightImg=new ImageIcon(rightURL);
    
        public static URL upURL=Images.class.getResource("/images/up.png");
        public static ImageIcon upImg=new ImageIcon(upURL);
    
    
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    StartGame类:

    package com.game;
    
    import javax.swing.*;
    import java.awt.*;
    
    public class StartGame {
        public static void main(String[] args) {
            /*1.创建一个窗体:*/
            JFrame jf = new JFrame();
            /*2.给窗体设置一个标题:*/
            jf.setTitle("贪吃蛇小游戏 by:cym");
            /*3.设置窗体弹出的坐标,对应窗体的宽和高:*/
    //        获取屏幕的宽、高
            int width = Toolkit.getDefaultToolkit().getScreenSize().width;
            int height = Toolkit.getDefaultToolkit().getScreenSize().height;
            jf.setBounds((width - 800) / 2, (height - 800) / 2, 800, 800);
            /*4.设置窗体大小不可调:*/
            jf.setResizable(false);
            /*5.关闭窗口的同时,程序随之关闭:*/
            jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    
            /*6.创建面板:*/
            GamePanel gp = new GamePanel();
    //        将面板放入窗体中:
            jf.add(gp);
    
            /*默认情况下窗体隐藏,需要进行显现(最好放在最后):*/
            jf.setVisible(true);
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    GamePanel类:

    package com.game;
    
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.util.Random;
    
    /*面板*/
    //继承JPanel才具备面板的功能,才成为一个面板
    public class GamePanel extends JPanel {
        /*定义两个数组:
         * 一个数组,专门存储蛇的x轴坐标
         * 一个数组,专门存储蛇的y轴坐标
         * */
        int[] snakeX = new int[200];
        int[] snakeY = new int[200];
        /*定义蛇的长度:*/
        int length;
    
        /*定义蛇的行走方向:*/
        String direction;
    
        /*游戏只有两个状态:开始、暂停*/
        boolean isStart = false;//默认游戏为暂停状态
    
        /*加入一个定时器:*/
        Timer timer;
    
        /*定义食物的xy轴坐标*/
        int foodX, foodY;
    
        /*定义一个积分:*/
        int score;
    
        /*加入一个变量,判断小蛇生死状态:*/
        boolean isDie = false;//默认小蛇为活着的状态
    
        /*自定义一个初始化方法,初始化小蛇的坐标:*/
        public void init() {
            /*初始化蛇的长度:*/
            length = 3;
            /*初始化蛇头坐标:*/
            snakeX[0] = 175;
            snakeY[0] = 275;
            /*初始化第一节身子坐标:*/
            snakeX[1] = 150;
            snakeY[1] = 275;
            /*初始化第二节身子坐标:*/
            snakeX[2] = 125;
            snakeY[2] = 275;
    
            /*初始化蛇头的方向为右:*/
            direction = "R";//上U 下D 左L 右R
    
            /*初始化食物的坐标:*/
            foodX = 300;
            foodY = 200;
    
            /*初始化积分:*/
            score = 0;
    
        }
    
    
        /*构造器,调用一下小蛇默认方法init(),进行面板初始化的时候就默认了蛇的位置:*/
        public GamePanel() {
            init();
    //        将焦点定位在当前操作的面板上
            this.setFocusable(true);
    //        加入监听:
    //        addKeyListener表示加入键盘监听
            this.addKeyListener(new KeyAdapter() {//涉及到适配器模式
                //            监听键盘按下操作
                @Override
                public void keyPressed(KeyEvent e) {
                    super.keyPressed(e);
                    int keyCode = e.getKeyCode();
    //                System.out.println(keyCode);//空格对应32
                    /*监听空格:*/
                    if (keyCode == KeyEvent.VK_SPACE) {//将空格32封装起来
                        if (isDie) {
    //                    全部恢复到初始化状态
                            init();
                            isDie = false;
                        } else {
                            isStart = !isStart;
                            repaint();//重绘
                        }
    
                    }
                    /*监听向上箭头:*/
                    if (keyCode == KeyEvent.VK_UP) {
                        direction = "U";
    
                    }
                    /*监听向下箭头:*/
                    if (keyCode == KeyEvent.VK_DOWN) {
                        direction = "D";
                    }
                    /*监听向左箭头:*/
                    if (keyCode == KeyEvent.VK_LEFT) {
                        direction = "L";
                    }
                    /*监听向右箭头:*/
                    if (keyCode == KeyEvent.VK_RIGHT) {
                        direction = "R";
                    }
    
                }
            });
    
            /*对定时器做初始化:*/
    //        延迟毫秒数、一个ActionListener类对象
            timer = new Timer(100, new ActionListener() {//创建ActionListener对象,一个匿名内部类
                //            ActionListener是 事件监听
    //            相当于每100ms监听你是否发生一个动作
    //            具体动作放入actionPerformed中
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (isStart && isDie == false) {//游戏开始状态、小蛇活着的状态下才动
    //                     由最后一节身子往前一节身子上动
                        for (int i = length - 1; i > 0; i--) {
                            snakeX[i] = snakeX[i - 1];
                            snakeY[i] = snakeY[i - 1];
                        }
    //                     动头的位置
                        if ("R".equals(direction)) {
                            snakeX[0] += 25;
                        }
                        if ("L".equals(direction)) {
                            snakeX[0] -= 25;
                        }
                        if ("U".equals(direction)) {
                            snakeY[0] -= 25;
                        }
                        if ("D".equals(direction)) {
                            snakeY[0] += 25;
                        }
    
    //                     防止蛇超出边界:
                        if (snakeX[0] > 725) {
                            snakeX[0] = 25;
                        }
                        if (snakeX[0] < 25) {
                            snakeX[0] = 725;
                        }
                        if (snakeY[0] < 75) {
                            snakeY[0] = 700;
                        }
                        if (snakeY[0] > 700) {
                            snakeY[0] = 75;
                        }
    
                        /*监测碰撞的动作,也就是吃食物的动作:*/
    //                     如果蛇头坐标与食物坐标一样时,即吃到食物
                        if (snakeX[0] == foodX && snakeY[0] == foodY) {
    //                         蛇长度加一
                            length++;
    //                         食物坐标改变,随机生成坐标,随机数必须是25的倍数,x轴【25,725】,y轴【75,700】
    //                         方法一:
    //                         math.random()-->[0.0,1.0)
    //                         math.random()*29-->[0.0,29.0)
    //                         (int)(math.random()*29)-->[0,28]
    //                         (int)(math.random()*29)+1-->[1,29]
                            foodX = ((int) (Math.random() * 29) + 1) * 25;//[1,29]*25=[25,725]
    //                         方法二:
    //                         [75,700]-->[3,28]*25
    //                         [3,28]-->[0,25]+3
    //                         [0,25]
    //                         new Random().nextInt(26)-->[0,26)-->[0,25]
                            foodY = ((new Random().nextInt(26)) + 3) * 25;//[3,28]*25=[75,700]
    
                            /*每吃到一次食物,积分加10*/
                            score += 10;
    
                        }
    
                        /*死亡判定:*/
                        for (int i = 1; i < length; i++) {
    //                         如果蛇头的坐标和身子的任意一节坐标一样
                            if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) {
    //                             判定为死亡状态
                                isDie = true;
                            }
    
    
                        }
    
                        repaint();//重绘,根据新的蛇头蛇身的位置画
                    }
                }
            });
    //        启动计时器
            timer.start();
        }
    
        /*此方法特殊,就相当于图形版的main方法,自动调用*/
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            /*1.填充背景颜色:*/
    //        颜色由rgb(red green blue)组成
    //        可通过点击左边行号旁的色块进行颜色修改
            this.setBackground(new Color(243, 239, 190, 255));
    
            /*2.画头部的图片header.png:*/
    //        Images.headerImg:调用图片类中的header.png图片
    //        paintIcon()方法将图片在面板中绘制出来
    //        this:当前面板
    //        g:使用的画笔
    //        x、y:对应坐标轴
            Images.headerImg.paintIcon(this, g, 15, 10);
    
            /*3.画一个矩形:*/
    //        先调节画笔颜色:
            g.setColor(new Color(205, 228, 246));
    //        fillRect填充矩形
            g.fillRect(15, 70, 750, 670);
    
    
            /*4.画小蛇:*/
    //        画蛇头:
            if ("R".equals(direction)) {
                Images.rightImg.paintIcon(this, g, snakeX[0], snakeY[0]);
            }
            if ("L".equals(direction)) {
                Images.leftImg.paintIcon(this, g, snakeX[0], snakeY[0]);
            }
            if ("U".equals(direction)) {
                Images.upImg.paintIcon(this, g, snakeX[0], snakeY[0]);
            }
            if ("D".equals(direction)) {
                Images.downImg.paintIcon(this, g, snakeX[0], snakeY[0]);
            }
    
            画第一节身子:
    //        Images.bodyImg.paintIcon(this,g,snakeX[1],snakeY[1]);
            画第二节身子:
    //        Images.bodyImg.paintIcon(this,g,snakeX[2],snakeY[2]);
    
    //        用循环来画蛇身子:
            for (int i = 1; i < length; i++) {
                Images.bodyImg.paintIcon(this, g, snakeX[i], snakeY[i]);
    
            }
    
            /*5.如果游戏是暂停的,界面中间有一个提示语*/
            if (isStart == false) {
                /*画一个文字:*/
    //            画笔设置颜色
                g.setColor(new Color(222, 13, 245));
    //            设置文字的字体、加粗、大小
                g.setFont(new Font("微软雅黑", Font.BOLD, 40));
    //            画文字:
    //            drawString()方法,画字符串
    //            文字内容、xy轴坐标
                g.drawString("点击空格开始游戏", 250, 330);
    
            }
    
            /*6.画食物:*/
            Images.foodImg.paintIcon(this, g, foodX, foodY);
    
            /*7.画积分(画文字):*/
            g.setColor(new Color(246, 245, 245));
            g.setFont(new Font("微软雅黑", Font.BOLD, 20));
            g.drawString("积分:" + score, 280, 40);
    
            /*8.画死亡状态:*/
            if (isDie) {
                g.setColor(new Color(246, 11, 11));
                g.setFont(new Font("微软雅黑", Font.BOLD, 35));
                g.drawString("小蛇死亡!游戏停止,按下空格重新开始游戏", 50, 330);
            }
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278

    贪吃蛇小游戏b站原视频:
    https://www.bilibili.com/video/BV1w5411g73U?share_source=copy_web

    贪吃蛇图片素材:
    链接:https://pan.baidu.com/s/1B5aIR-luqF94Y-8Lhwck0g?pwd=5gj9
    提取码:5gj9
    解压缩密码:456654

    我的jar包:
    链接:https://pan.baidu.com/s/1Zk31sOPTr_WCidZUd2Jl9A?pwd=4h7d
    提取码:4h7d

    若双击jar包不能够直接运行的解决办法:
    指路我的博客:http://t.csdn.cn/1QALL

  • 相关阅读:
    单机Centos7搭建mysql5.7主备/主从(docker)
    嵌入式程序开发3
    vue 代理
    阿里云开发者社区有奖征文活动,期待您出文相助
    定制qga(作业截图)
    web前端-html-css-overflow
    首次失败后,爱美客第二次冲刺港交所上市,财务负责人变动频繁
    【1++的C++进阶】之emplace详解
    期末前端web大作业——名侦探柯南网页制作 Hbuiderx制作网页 静态HTML网页单页制作 dreamweaver网页设计与制作代码 web前端期末大作业
    vue组件使用与父子传递
  • 原文地址:https://blog.csdn.net/weixin_47678894/article/details/125454495