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

article/2025/10/15 12:10:15

一、引入

涉及技能:

  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);}

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);}
}

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

六、创建面板

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

package com.game;import javax.swing.*;
import java.awt.*;/*面板*/
//继承JPanel才具备面板的功能,才成为一个面板
public class GamePanel extends JPanel {/*此方法特殊,就相当于图形版的main方法,自动调用*/@Overrideprotected 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);}
}

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.在面板类中的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();}

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.定义蛇头的方向,代码如下。

/*定义两个数组:* 一个数组,专门存储蛇的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}

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]);}

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

具体代码如下:

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

十、小蛇向右动起来

具体代码如下:

/*加入一个定时器:*/Timer timer;
/*构造器,调用一下小蛇默认方法init(),进行面板初始化的时候就默认了蛇的位置:*/public GamePanel(){init();
//        将焦点定位在当前操作的面板上this.setFocusable(true);
//        加入监听:
//        addKeyListener表示加入键盘监听this.addKeyListener(new KeyAdapter() {//涉及到适配器模式
//            监听键盘按下操作@Overridepublic void keyPressed(KeyEvent e) {super.keyPressed(e);int keyCode = e.getKeyCode();
//                System.out.println(keyCode);//空格对应32if (keyCode==32){
//                    System.out.println("点击了空格");isStart=!isStart;//点击了空格,将isStart变成相反的状态repaint();//重绘,调用paintComponent方法}}});/*对定时器做初始化:*/
//        延迟毫秒数、一个ActionListener类对象timer=new Timer(100, new ActionListener() {//创建ActionListener对象,一个匿名内部类
//            ActionListener是 事件监听
//            相当于每100ms监听你是否发生一个动作
//            具体动作放入actionPerformed中@Overridepublic 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();}

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

代码如下:

 /*构造器,调用一下小蛇默认方法init(),进行面板初始化的时候就默认了蛇的位置:*/public GamePanel(){init();
//        将焦点定位在当前操作的面板上this.setFocusable(true);
//        加入监听:
//        addKeyListener表示加入键盘监听this.addKeyListener(new KeyAdapter() {//涉及到适配器模式
//            监听键盘按下操作@Overridepublic 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中@Overridepublic 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.画食物代码:

/*定义食物的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;}
 /*6.画食物:*/    Images.foodImg.paintIcon(this,g,foodX,foodY);

2.吃食物代码:

 /*对定时器做初始化:*/
//        延迟毫秒数、一个ActionListener类对象timer=new Timer(100, new ActionListener() {//创建ActionListener对象,一个匿名内部类
//            ActionListener是 事件监听
//            相当于每100ms监听你是否发生一个动作
//            具体动作放入actionPerformed中@Overridepublic 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();}

十三、画积分

代码如下:

 /*定义一个积分:*/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;}
 /*监测碰撞的动作,也就是吃食物的动作:*/
//                     如果蛇头坐标与食物坐标一样时,即吃到食物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();//重绘,根据新的蛇头蛇身的位置画}}});
  /*7.画积分(画文字):*/g.setColor(new Color(246, 245, 245));g.setFont(new Font("微软雅黑",Font.BOLD,20));g.drawString("积分:"+score,280,40);

十四、死亡判定

        /*初始化积分:*/score=0;
 @Overridepublic 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();//重绘}}
 @Overridepublic 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];}
  /*死亡判定:*/for(int i=1;i<length;i++){
//                         如果蛇头的坐标和身子的任意一节坐标一样if (snakeX[0]==snakeX[i]&&snakeY[0]==snakeY[i]) {
//                             判定为死亡状态isDie=true;}
 /*8.画死亡状态:*/if(isDie){g.setColor(new Color(246, 11, 11));g.setFont(new Font("微软雅黑",Font.BOLD,35));g.drawString("小蛇死亡!游戏停止,按下空格重新开始游戏",50,330);

十五、游戏打包

在对方电脑有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);}

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);}
}

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() {//涉及到适配器模式//            监听键盘按下操作@Overridepublic 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中@Overridepublic 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方法,自动调用*/@Overrideprotected 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);}}
}

贪吃蛇小游戏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


http://chatgpt.dhexx.cn/article/rGsWwbsK.shtml

相关文章

安卓蓝牙开发总结(一)—蓝牙开启与关闭

蓝牙开启与关闭 1、引言2、布局文件3、蓝牙打开与关闭  3.1 通过对按钮监听方法  3.2 通过设置点击事件 4、结果展示及总结5、参考链接 1、引言 最近在学习如何在安卓手机上对蓝牙进行操控&#xff0c;作为初学者发现大多数博客对安卓开发的初学者极为不友好&#xff0c;特…

【Bluetooth|蓝牙开发】二、蓝牙开发入门

个人主页&#xff1a;董哥聊技术 我是董哥&#xff0c;嵌入式领域新星创作者 创作理念&#xff1a;专注分享高质量嵌入式文章&#xff0c;让大家读有所得&#xff01; 【所有文章汇总】 1、蓝牙基础概念 蓝牙&#xff0c;是一种利用低功率无线电&#xff0c;支持设备短距离…

nimble 蓝牙开发一:BLE 蓝牙 Host 规范概述

目录 nimble 蓝牙开发一&#xff1a;概述一、BLE 简介二、BLE 基础知识蓝牙设备地址BLE 广播类型标准广播数据 三、BLE 工作概述BLE 常见的操作有&#xff1a;BLE 常见的工作流程&#xff1a; 四、BLE 使用的协议规范GAP1. GAP 工作角色2. GAP 工作模式3. GAP 工作流程4. GAP 工…

ESP32 蓝牙开发

1. 低功耗蓝牙&#xff08;BLE&#xff09;协议栈 低功耗蓝牙协议是蓝牙通信协议的一种&#xff0c;BLE协议栈就是实现低功耗蓝牙协议的代码 1.1 层次协议 蓝牙协议规定了两个层次的协议&#xff0c;分别为蓝牙核心协议&#xff08;Bluetooth Core&#xff09;和蓝牙应用层协…

Android蓝牙开发 — 经典蓝牙BLE蓝牙

一&#xff0c;前期基础知识储备 1&#xff09;蓝牙是一种支持设备之间短距离通信的无线电技术&#xff08;其他还包括红外&#xff0c;WIFI&#xff09;&#xff1b; 支持移动电话、笔记本电脑、无线耳机等设备之间进行信息的交换&#xff1b; Android支持的蓝牙协议栈&…

Android 蓝牙开发——概述(一)

一、蓝牙简介 蓝牙技术是一种无线数据和语音通信开放的全球规范,它是基于低成本的近距离无线连接,为固定和移动设备建立通信环境的一种特殊的近距离无线技术连接。 其中将1.x~3.0之间的版本称之为经典蓝牙,4.x开始的蓝牙称之为低功耗蓝牙,也就是蓝牙BLE。 1、蓝牙协议介绍…

低功耗蓝牙开发入门概念科普

一、概述 1、缘起 低功耗蓝牙起源于Bluetooth4.0版本&#xff0c;至今已发展到5.3 4.0 bluetooth low enerngy 这个阶段低功耗蓝牙的基础框架已经稳定成型&#xff0c;后面版本主要退出新特性和扩展特性&#xff0c;同时保证和4.0的原生兼容性 4.1 multi role&#xff08;主从…

ESP32开发三_蓝牙开发

蓝牙开发 交流QQ: 1048272975 QQ交流群: 636564526 蓝牙是一种不断创新发展的无线通信技术标准&#xff0c;采用了2.4G ISM频段&#xff0c;在音频传输、数据传输、位置服务、设备组网这些场景有着广泛的应用。 1. 蓝牙概述 蓝牙技术分经典蓝牙(Classic BT)和低…

iOS 蓝牙开发实现文件传输

这是一篇旧文&#xff0c;三年前就写过了&#xff0c;一直没有时间分享出来&#xff0c;最近简单整理了下&#xff0c;希望能帮到有需要的人。   由于我这里没有相关的蓝牙设备&#xff0c;主要用了两个手机&#xff0c;一个作为主设备&#xff0c;一个做为从设备。另外进行蓝…

Android经典蓝牙开发全流程

一、基本介绍 所谓蓝牙(Bluetooth)技术&#xff0c;实际上是一种短距离无线电技术&#xff0c;最初是由爱立信公司公司发明的。技术始于爱立信公司 1994 方案&#xff0c;它是研究在移动电话和其他配件间进行低功耗、低成本无线通信连接的方法。发明者希望为设备间的通讯创造一…

Android - 蓝牙开发

文章目录 科普SIG类型制式选择逻辑链路控制适配协议 (L2CAP)L2CAP的功能 蓝牙框架和 RFCOMM 协议蓝牙安全白名单机制 编程蓝牙权限Classic BluetoothBluetooth Low Energy术语角色 & 职能查找 BLE 设备连接设备上的 GATT 服务器绑定服务蓝牙设置连接到设备连接到 GATT 服务…

Android 蓝牙开发 uuid,Android蓝牙开发之 UUID

UUID&#xff1a;全球唯一标识符 在蓝牙中&#xff0c;每个Service和Characteristic都唯一地由"全球唯一标识符" (UUID)来校验&#xff0c;主要是保证他们的唯一性。 UUID可分为&#xff1a;16位、32位、128 位UUID Bluetooth_Base_UUID&#xff1a;蓝牙UUID基数 UUI…

Android 低功耗蓝牙开发简述

低功耗蓝牙简述 一、什么是低功耗蓝牙&#xff1f;二、怎么做低功耗蓝牙应用&#xff1f;① 之前有没有接触Android蓝牙开发&#xff1f;② 蓝牙设备固件是公司自己的吗&#xff1f;③ 有没有蓝牙固件和蓝牙应用的文档和Demo&#xff1f;④ 具体的业务功能需求明确吗&#xff1…

Android蓝牙开发

题引&#xff1a; 最近项目上涉及与硬件相关的功能&#xff0c;需要通过蓝牙进行消息收发。项目已完成&#xff0c;这里做下记录。 通信步骤&#xff1a; 1.初始化BluetoothAdapter.getDefaultAdapter()获取BluetoothAdapter对象 2.判断蓝牙是否开启bluetoothAdapter.isEnab…

【Android】蓝牙开发——BLE(低功耗蓝牙)(附完整Demo)

目录 目录 前言 一、相关概念介绍 二、实战开发 三、项目演示 四、Demo案例源码地址 五、更新记录 1、2020/12/29 &#xff1a;修改 setupService()中错误 2、2021/05/14 &#xff1a;更新连接方法&#xff08;解决部分蓝牙设备连接失败的问题&#xff09; 3、2022/1…

【Bluetooth开发】蓝牙开发入门

BLE 蓝牙设备在生活中无处不在&#xff0c;但是我们也只是将其作为蓝牙模块进行使用&#xff0c;发送简单的AT命令实现数据收发。 那么&#xff0c;像对于一些复杂的使用场合&#xff1a;“车载蓝牙”、"智能手表"、“蓝牙音箱”等&#xff0c;我们不得不去了解底层…

【Bluetooth蓝牙开发】一、蓝牙开发入门

一、蓝牙开发入门 文章目录 一、蓝牙开发入门 1、蓝牙概念2、蓝牙发展历程3、蓝牙技术概述 3.1 Basic Rate(BR)3.2 Low Energy&#xff08;LE&#xff09; 4、常见蓝牙架构 4.1 SOC蓝牙单芯片方案4.2 SOC蓝牙MCU方案4.3 蓝牙host controller分开方案4.4 使用场景 5、参考文档 …

vs2012做ArcGIS二次开发前期准备

解压ArcGIS 1.双击ESRI 2.点击 一路next&#xff0c;自己选择安装路径&#xff0c;建议放在非系统盘 3.开始菜单-ArcGIS-License Server Administrator 4.点击“stop/停止"&#xff0c;再点击确定 5.将破解文件中的两个文件拷到D:\Program Files (x86)\ArcGIS\License10.…

arcgis 二次开发学习笔记(一):了解二次开发有关的软件及其之间的关系

【废话篇】今天是大三开学的第一天课&#xff0c;终于意识到我口中念念不忘却没付出实际行动的“考研”来了。考研目标现在为止还没有很明确&#xff0c;只是不甘屈于人后。周围太多生活得很辛苦的人&#xff0c;只是不愿意我这一辈子也为了有关qian的小事斤斤计较&#xff0c;…

Arcobjects for java:Arcgis二次开发入门,开发一个基本地图组件

一、目的 因学习需要&#xff0c;使用Java进行Arcgis二次开发。当前对arcgis进行二次开发使用的语言基本是C#&#xff0c;使用Java对Arcgis进行二次开发的很少。于是使用java在idea上进行Arcgis二次开发&#xff0c;给入门的同学做参考&#xff0c;我自己也处于入门阶段&#…