基于Java的贪吃蛇小游戏

2023-11-05

一、开发思路

    设定一个一定大小的且大小不可变的游戏窗口

    在创建的窗口上绘制游戏的基本面板样式

    使用提前保存的素材图标绘制一条静态的小蛇

    使小蛇能够移动;实际只需蛇头坐标移动,每节身体覆盖前一节身体坐标,设置定时器Timer timer =new Timer();监听时间让小蛇能移动

    监听键盘操作,使用户能通过键盘控制蛇的方向

    定义一个食物坐标,用random随机数类实现食物随机生成

    小蛇吃到食物时身体长度+1,实际是蛇头坐标与食物坐标重合时

    boolean定义游戏失败的判断,当蛇头与任何身体部位坐标重合(或撞到边界)则游戏失败,可再设置积分系统,每吃到一次食物加一定分数
二 新建一个Data类,作为图片资源

package snake;

import java.net.URL;

import javax.swing.ImageIcon;

public class Data {

    public static URL headerURL = Data.class.getResource("/statics/header.png");
    public static ImageIcon header;

    static {
        assert headerURL != null;
        header = new ImageIcon(headerURL);
    }

    public static URL upURL = Data.class.getResource("/statics/up.png");
    public static URL downURL = Data.class.getResource("/statics/down.png");
    public static URL leftURL = Data.class.getResource("/statics/left.png");
    public static URL rightURL = Data.class.getResource("/statics/right.png");

    public static ImageIcon up = new ImageIcon(upURL);
    public static ImageIcon down = new ImageIcon(downURL);
    public static ImageIcon left = new ImageIcon(leftURL);
    public static ImageIcon right = new ImageIcon(rightURL);

    public static URL bodyURL = Data.class.getResource("/statics/body.png");
    public static ImageIcon body;

    static {
        assert bodyURL != null;
        body = new ImageIcon(bodyURL);
    }

    public static URL foodURL = Data.class.getResource("/statics/food.png");
    public static ImageIcon food;

    static {
        assert foodURL != null;
        food = new ImageIcon(foodURL);
    }

}

三 绘制静态游戏窗口

package snake;


import javax.swing.JFrame;
import javax.swing.WindowConstants;
//创建主窗口
public class MainFrame{

    public MainFrame(){
        init();
    }

    public void init(){
        JFrame frame = new JFrame();

        frame.setSize(915, 745);
        frame.setResizable(false);//窗口不可拉伸
        frame.setTitle("贪吃蛇小游戏");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        frame.add(new GamePanel());

        frame.setVisible(true);
    }
}

四 游戏面板类 GamePanel

package snake;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;

import javax.swing.JPanel;
import javax.swing.Timer;

//游戏面板
public class GamePanel extends JPanel implements ActionListener{

    //定义游戏数据
    int panel_Width;
    int panel_Height;

    int snake_Speed = 300;//刷新时间

    //定义蛇的数据结构
    int length;	//蛇的长度
    int[] snake_X = new int[600];
    int[] snake_Y = new int[600];
    String snake_Orientation; 	//蛇头朝向

    //食物的坐标
    int food_X;
    int food_Y;
    Random random = new Random();

    //定义游戏状态
    boolean isStrat = false; //默认暂停状态

    //游戏失败
    boolean isFail = false;

    //游戏积分
    int score;
    int food_Value;//食物分数

    //游戏难度
    int level;

    //cheat
    boolean cheat = false;

    //定时器
    Timer timer = new Timer(snake_Speed, this);

    //构造器
    public GamePanel() {
        init();
        //获得焦点和键盘事件
        this.setFocusable(true);	//获得焦点事件
        this.addKeyListener(new keyboardListener());
        timer.start();//游戏一开始,定时器就启动
    }

    //初始化
    public void init(){
        panel_Width = 850;
        panel_Height = 600;

        length = 3;
        snake_X[0] = 100;snake_Y[0] = 100;	//头的坐标
        snake_X[1] = 75;snake_Y[1] = 100;	//第一节身体的坐标
        snake_X[2] = 50;snake_Y[2] = 100;	//第二节身体的坐标
        snake_Orientation = "right";	//初始头的方向为右

        //食物随机分布在界面上

        food_X = 25 + 25*random.nextInt(33);//生成1到34的随机数
        food_Y = 75 + 25*random.nextInt(23);

        score = 0;
        food_Value = 5;

        level = 1;
    }


    @Override
    protected void paintComponent(Graphics g) {

        super.paintComponent(g);//清屏

        //绘制静态面板
        this.setBackground(Color.lightGray);

        //画下方游戏界面
        g.fillRect(25, 75, panel_Width, panel_Height);

        //画积分
        g.setColor(Color.white);
        g.setFont(new Font("微软雅黑", Font.BOLD, 15));
        g.drawString("长度:"+length, 750, 25);
        g.drawString("分数:"+score, 750, 40);
        g.drawString("难度:"+level, 750, 55);
        g.drawString("~糖豆人大作战~", 370, 30);


        //画食物
        Data.food.paintIcon(this, g, food_X, food_Y);

        //画小蛇
        if (snake_Orientation.equals("right")){
            Data.right.paintIcon(this, g, snake_X[0], snake_Y[0]);//画朝右的头部
        }else if(snake_Orientation.equals("left")){
            Data.left.paintIcon(this, g, snake_X[0], snake_Y[0]);//画朝左的头部
        }else if(snake_Orientation.equals("up")){
            Data.up.paintIcon(this, g, snake_X[0], snake_Y[0]);//画朝上的头部
        }else if(snake_Orientation.equals("down")){
            Data.down.paintIcon(this, g, snake_X[0], snake_Y[0]);//画朝下的头部
        }

        for (int i = 1; i < length; i++) {
            Data.body.paintIcon(this, g, snake_X[i], snake_Y[i]);//画每一节身体
        }


        //游戏状态
        if (isStrat == false){
            g.setColor(Color.white);
            g.setFont(new Font("微软雅黑", Font.BOLD, 40));
            g.drawString("按下空格开始游戏", 300, 300);
        }

        //游戏失败
        if (isFail == true){
            g.setColor(Color.red);
            g.setFont(new Font("微软雅黑", Font.BOLD, 40));
            g.drawString("失败,按下空格重新开始", 220, 300);
        }

    }

    //键盘监听
    class keyboardListener extends KeyAdapter{
        @Override
        public void keyPressed(KeyEvent e) {
            int keyCode = e.getKeyCode();//获得按下的键
            if (keyCode == KeyEvent.VK_SPACE){
                if (isFail == true){
                    //空格控制重新开始
                    isFail = false;
                    init();
                }else {
                    //空格控制游戏暂停
                    isStrat = !isStrat;	//isStart取反
                }
                repaint();
            }

            //控制小蛇移动
            if (keyCode == KeyEvent.VK_UP){
                if (snake_Orientation != "down"){
                    snake_Orientation = "up";
                }
            }else if (keyCode == KeyEvent.VK_DOWN){
                if (snake_Orientation != "up"){
                    snake_Orientation = "down";
                }
            }else if (keyCode == KeyEvent.VK_LEFT){
                if (snake_Orientation != "right"){
                    snake_Orientation = "left";
                }
            }else if (keyCode == KeyEvent.VK_RIGHT){
                if (snake_Orientation != "left"){
                    snake_Orientation = "right";
                }
            }

            if (keyCode == KeyEvent.VK_C){
                cheat = !cheat;
            }
        }
    }

    //事件监听,通过固定的时间来刷新
    @Override
    public void actionPerformed(ActionEvent e) {
        if (isStrat == true && isFail == false){	//游戏开始,小蛇运动
            //身体跟随移动
            for (int i = length-1; i > 0; i--) {//向前移动一节(每个身体都到上一节身体的坐标)
                //新生成的身体不可见,否则有bug
                snake_X[length] = -50;
                snake_Y[length] = -50;

                snake_X[i] = snake_X[i-1];
                snake_Y[i] = snake_Y[i-1];
            }
            //头部运动判断,只需要控制头部的运动,其他身体都会跟着动
            if (snake_Orientation == "up"){
                snake_Y[0] = snake_Y[0]-25;
                if (snake_Y[0] < 75){
                    snake_Y[0] = panel_Height+50;
                }
            }else if (snake_Orientation == "down"){
                snake_Y[0] = snake_Y[0]+25;
                if (snake_Y[0] > panel_Height+50){
                    snake_Y[0] = 75;
                }
            }else if (snake_Orientation == "left"){
                snake_X[0] = snake_X[0]-25;
                if (snake_X[0] < 25){
                    snake_X[0] = panel_Width;
                }
            }else if (snake_Orientation == "right"){
                snake_X[0] = snake_X[0]+25;
                if (snake_X[0] > panel_Width){
                    snake_X[0] = 25;
                }
            }

            //吃食物
            if (snake_X[0] == food_X && snake_Y[0] == food_Y) {
                length++;
                score += food_Value;
                //重新生成食物
                food_X = 25 + 25 * random.nextInt(34);
                food_Y = 75 + 25 * random.nextInt(24);
            }

            //失败判定,头碰到身体就算失败
            if (cheat == false){
                for (int i = 1; i < length; i++) {	//遍历所有身体坐标
                    if (snake_X[0] == snake_X[i] && snake_Y[0] == snake_Y[i]){
                        isFail = true;
                        break;
                    }
                }
            }

            if (length > 5 && length < 10){
                level = 2;
                timer.stop();
                snake_Speed = 100;
            }
            if (length > 20 && length < 30){
                level = 3;
                timer.stop();
                snake_Speed = 50;
            }

            repaint();
        }
        timer.start();
    }

}

1. 游戏规则:蛇头碰到蛇身结束游戏

2. 根据积分等级,蛇的移动速度加快,积分越高,移动速度越快

3. 键盘:上下左右键控制蛇的移动方向

五 最后一个类,启动类 StartGame

package snake;
public class StartGame {
    public static void main(String[] args) {
        new MainFrame();
    }
}

六、效果截图

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于Java的贪吃蛇小游戏 的相关文章

  • @TableGenerator 的初始值属性在 Hibernate 中显示问题,但在 JPA 中则不然

    package com sb firstjpaexample pojo import javax persistence Column import javax persistence Entity import javax persist
  • SPNEGO 密码身份验证问题

    我已将我的应用程序配置为通过 SPNEGO 与 Websphere 使用 Kerberos 身份验证 这是详细信息 krb5 conf libdefaults default realm ABC MYCOMPANY COM default
  • 将构造函数作为参数传递给方法

    我是java新手 开始研究构造函数 我看到一些构造函数作为参数传递给方法的示例 请告诉我当构造函数作为参数传递给方法时会发生什么 或者建议我一些链接 我可以在其中获得有关使用构造函数的足够知识 根据您需要传递构造函数的目的 您可以考虑传递供
  • 将 MouseListener 添加到面板

    我正在尝试将鼠标操作添加到我的面板中 这就是程序应该做的事情 编写一个程序 允许用户通过按三下鼠标来指定一个三角形 第一次按下鼠标后 画一个小点 第二次按下鼠标后 绘制一条连接前两个点的线 第三次按下鼠标后 绘制整个三角形 第四次按下鼠标会
  • 在 jTextfield 中禁用“粘贴”

    我有一个用 Swing awt 编写的应用程序 我想阻止用户将值粘贴到文本字段中 有没有办法在不使用动作监听器的情况下做到这一点 您可以使用 null 参数调用 setTransferHandler 如下所示 textComponent s
  • 如何作为应用程序发布到页面?

    所以 我有一个应用程序 Facebook 应用程序实体 并且我有一个页面 我想使用应用程序通过java代码 通过restfb或任何其他建议 发布到页面 看起来我错过了页面授予应用程序发布权限的阶段 不知道该怎么做 谢谢你们 乌里 您只能 作
  • 使用 Apache POI Excel 写入特定单元格位置

    如果我有一个未排序的参数 x y z 列表 是否有一种简单的方法将它们写入使用 POI 创建的 Excel 文档中的特定单元格 就好像前两个参数是 X 和Y 坐标 例如 我有如下行 10 4 100 是否可以在第 10 行第 4 列的单元格
  • Java 卡布局。多张卡中的一个组件

    一个组件 例如JLabel 在多张卡中使用CardLayout 目前看来该组件仅出现在它添加到的最后一张卡上 如果有办法做到这一点 我应该吗 这是不好的做法吗 或者有其他选择吗 你是对的 它只出现在 添加到的最后一张卡 中 但这与CardL
  • 运行 java -jar 时出现 java.lang.ClassNotFoundException

    我正在使用 ant 来构建我的build xml文件 它编译正常 但随后得到运行时java lang NoClassDefFoundError通过 运行生成的 jar 时java jar my jar jar 似乎这个问题出现了很多 但没有
  • 我需要在 JFileChooser(打开模式)中显示不带扩展名的文件名。如何?

    我在打开模式下使用 JFileChooser 我需要显示不带扩展名的 文件名 字段 如何 我知道文件视图 它删除文件系统文件中的扩展名 但将所选文件中的扩展名保留在 文件名 字段中解释 http saveimg ru show image
  • java setFullScreenWindow 在 Mac 中隐藏登录对话框

    我使用的是全屏窗口 类似于屏幕保护程序 使用这里的方法 GraphicsEnvironment getLocalGraphicsEnvironment getDefaultScreenDevice setFullScreenWindow t
  • Struts 1 到 Spring 迁移 - 策略

    我有一个legacy银行应用程序编码为Struts 1 JSP现在的要求是迁移后端 目前为 MVC to Springboot MVC 后续UI JSP 将迁移到angular Caveats 1 后端不是无状态的 2 会话对象中存储了大量
  • 如何在 JPA 和 Hibernate 中将数据库生成的列值定义为只读字段?

    使用 MariaDB 10 2 可以定义日期时间的默认值 例如创建和最后修改 我应该如何将此列作为只读字段访问 因为这个值应该只在数据库的控制之下 并且不应该从代码中修改 但我想在代码中读取这个属性 这很简单 只需设置insertable
  • 插入时的 iBatis 判别器

    我有一个抽象类Example以及与之相伴的具体子类 我使用鉴别器来提取数据out数据库的 像这样
  • 在尝试使用 GPS 之前如何检查 GPS 是否已启用

    我有以下代码 但效果不好 因为有时 GPS 需要很长时间 我该如何执行以下操作 检查GPS是否启用 如果启用了 GPS 请使用 GPS 否则请使用网络提供商 如果 GPS 时间超过 30 秒 请使用网络 我可以使用时间或 Thread sl
  • C 与 C++ 中的 JNI 调用不同?

    所以我有以下使用 Java 本机接口的 C 代码 但是我想将其转换为 C 但不知道如何转换 include
  • 如何使用Gson仅从Json反序列化某些特定字段?

    我有以下 JSON 字符串 channel bvmt initValues data value instrumentIds TN0007250012 TN0007500010 instruments mnemonic ADWYA marc
  • Collections.sort(list) 和 list.sort(Comparator) 之间的区别

    有什么理由让我应该选择Collections sort list 方法而不是简单地调用list sort 内部Collections sort只是调用sort的方法List无论如何 上课 令人惊讶的是几乎每个人都告诉我使用Collectio
  • spring data jpa复合键重复键记录插入导致更新

    我有一个具有复合键的实体 我试图通过使用 spring data jpa 存储库到 mysql 数据库来持久化它 如下所示 Embeddable public class MobileVerificationKey implements S
  • mybatis:使用带有 XML 配置的映射器接口作为全局参数

    我喜欢使用 XML 表示法来指定全局参数 例如连接字符串 我也喜欢 Mapper 注释 当我尝试将两者结合起来时 我得到这个例外 https stackoverflow com questions 4263832 type interfac

随机推荐

  • 项目打包报不能在脱机状态下访问**资源

    项目场景 springboot项目 使用maven进行打包操作 问题描述 Failed to execute goal org springframework boot spring boot maven plugin 2 5 0 repa
  • UE4_UStruct 遍历

    一个结构体中存在一个Val变量 Val变量的类型是FVector4 想从c 层面去遍历获得Val的值 上图是很早之前的一个Property继承关系图 当然 在4 25UProperty被FProperty夺笋 好处呢 见下 没有继承UObj
  • etcd的使用

    启动etcd服务 启动etcd时最主要的是需要准备两个没有使用过的端口 这两个端口一个用于etcd之间同步信息 一个用于etcd向客户端提供服务的端口 因此启动单个etcd节点 只需按照如下命令行输入即可 server name myetc
  • sigmoid & logistic

    1 吴恩达老师视频中说sigmoid函数就是logistic函数 2 查阅复旦大学邱锡鹏老师关于深度学习的书 在第四章中写道 Sigmoid型函数是指一类S型曲线函数 为两端饱和函数 常用的Sigmoid型函数有Logistic函数和Tan
  • OpenPose笔记——windows 10下,自编译openpose代码(vs下能跑了,pythonAPI也能使了)

    简直太可怕了 遇到N多的问题 我觉有必要写下来记录一下 我自己编译了四五天 编译了10几次 夭寿哦 缺好多好多东西 给大家讲一下具体步骤 一 准备工作 准备工作当然是各种环境 1 至少VS2015 以上的版本 2 CMake Gui 注意
  • 问题定义过程

    问题定义过程由四步组成 确立需求 证明需求 理解问题和它的上下文和问题陈述 这个模型的主要优点是能够帮助你确定和理解问题的细节 帮助你了解组织的使命和战略在问题解决过程中的的重要性 从这里你可以确定问题是否值得努力寻求解决方案 只有明白了问
  • 自顶向下 逐步求精

    将复杂的大问题分解为相对简单的小问题 找出每个问题的关键 重点所在 然后用精确的思维定性 定量地去 描述问题 其核心本质是 分解 自顶向下 top down 的分析算法通过在最左推导中描述出各个步骤来分析记号串输入 之所以称这样的算法为自顶
  • 埋点系统:详解设计埋点过程中的“who when where how what”

    上次写了一篇 如何用数据驱动产品迭代 其中提到了一点设计埋点的方法 很多朋友留言说需要设计埋点的指南 像我这种从来不拒需求的人 这两天下班闲下来之后就整理了一下埋点设计的一些知识 希望能有所帮助 在诸多招聘 JD 中提到的数据分析能力 主要
  • 使用raspberry pi pico 制作红绿灯

    需要的东西 一块面包版 一块raspberry pi pico 红绿黄led灯各一颗 220欧电阻3只 若干线 编程软件 thonny 操作系统 deepin 23 结果展示 使用raspberry pi pico 制作红绿灯 from m
  • 金山云服务器异常,金山云-文档中心-金山云告诉你:找不到服务器或dns错误怎么办...

    我们在用电脑 会经常使用浏览器 不少人经常在浏览网页时候突然跳出一个提示 上面显示 找不到服器 或 dns错误 下面 给大家分享找不到服务器或dns错误的解决经验 1 病毒所致 如果你电脑中了病毒 让你的DNS被劫持 比如自己的浏览器主页被
  • 【毕业设计】基于PLC的十字路口交通灯控制系统设计【仿真+源码+论文】

    摘 要 本次设计的课题是基于PLC的十字路口交通灯控制系统设计 传统的十字路口交通灯多采用单片机集成电路作为控制系统 单片机系统虽然在功能上能够实现十字路口交通灯的各种控制需求 但是单片机控制系统在设计时需要数字电路与模拟电路的完美结合 这
  • 基于跳表实现的轻量级KV存储引擎 项目总结

    参考 https github com youngyangyang04 Skiplist CPP 项目介绍 KV存储引擎 众所周知 非关系型数据库redis 以及levedb rockdb其核心存储引擎的数据结构就是跳表 本项目就是基于跳表
  • 5.0 Vue中使用webpack

    文章目录 webpack的基本使用 webpack中的插件 webpack打包发布 Source Map 注意 在实际开发中我们并不需要自己配置 webpack webpack中 的用法 在Chrome浏览器中安装vue devtools调
  • QT书籍分享——最全资料汇总

    QT从入门到精通 学习路线 市面上QT学习的书籍也挺多的 今天从学习路径上给大家一一盘点一下 并附上相关链接 大家可以根据需求下载哦 1 语言基础学习 学习QT最最最基础的当然是语言学习了 可以选择C 语言 也可以选择Python语言 C
  • 佛祖保佑,永无bug——springboot项目启动图案的修改方法

    在resources目录 与application yml文件同级目录 下创建banner txt文件 将下面的代码复制进去就好了 AnsiColor BRIGHT YELLOW ooOoo o8888888o
  • 动态规划-各种题型及思路整理(自用笔记,大神绕道)

    目录 简介 分类 基本思想 基本思路 状态转移方程 适用条件 一句话总结 应用 前缀和思想 简介 动态规划 dynamic programming 简称dp 是运筹学的一个分支 是求解决策过程 decision process 最优化的数学
  • 21天学习挑战赛——Python操作MySQL和SqlServer

    目录 1 pymysql模块 2 pymysql模块使用说明 2 1 pymysql操作流程图 2 2 创建连接对象 2 3 获取游标对象 2 4 用法举例 2 4 1 获取一条数据 6 4 2 获取多条数据 6 4 3 对数据进行增删改操
  • 未来社交媒体的变革者

    近日 Meta宣布了其认可的七大社交媒体趋势 这些趋势代表了未来社交媒体发展的核心方向 这些趋势中 生成式AI AR VR营销等引人注目的技术入选 预示着我们即将迎来全新的社交媒体时代 一 生成式AI 像人一样理解并回应 近年来 生成式AI
  • linux 非root用户 安装pyscipopt

    前提 实验室的服务器 我没有root权限 1 尝试用conda方法onda install channel conda forge pyscipopt 出现未知错误 搜遍百度谷歌stackoverflow都没有找到有人和我一样的问题 不知道
  • 基于Java的贪吃蛇小游戏

    一 开发思路 设定一个一定大小的且大小不可变的游戏窗口 在创建的窗口上绘制游戏的基本面板样式 使用提前保存的素材图标绘制一条静态的小蛇 使小蛇能够移动 实际只需蛇头坐标移动 每节身体覆盖前一节身体坐标 设置定时器Timer timer ne