贪吃蛇项目的制作

该项目是根据GUI编程学习所写,详细的学习课程可以参考狂神说老师的GUI课程:一小时开发贪吃蛇

以下仅仅为简要说一下 逻辑,源码放在最后。

实现该项目总共用到三个类: Data数据类,用于存放静态数据; Snake实现类,用于运行; GamePanel核心类,用于具体实现内部逻辑。

实现结果如图:

贪吃蛇项目的制作

Data类

要实现以上的内容,我们需要一些静态图片资源,包括蛇头蛇身,介绍图等,该类就是为了存放这些而设计的,如开头广告栏的存储:

public static URL headURL = Data.class.getResource("/StaticFile/header.png");
public static ImageIcon header = new ImageIcon(headURL);

由于这些均为静态资源,使用static进行存储。

Snake类

该类为运行类,直接调用GamePanel核心类进行运行。它继承了JFrame类,即一个最外层的窗口,只是在窗口中使用 frame.add(new GamePanel());添加了面板,而该面板GamePanel即为真正的实现功能的类

GamePanel类

该类为真正的实现类。

实现贪吃蛇功能,我们要明确一点:表面上看见贪吃蛇一格一格动,实际上是 整个图片在一次一次变化。每一次贪吃蛇的移动,象征的是 面板的一次更新

所以逻辑很清晰了,要实现功能, 先实现静态再实现动态

先直接在这里写上在该类中我用到的变量,便于后面大家对照分别是什么意思:

    //定义蛇的数据结构
    int length;//蛇的长度
    String direct;//蛇的方向
    int[] snakeX = new int[600];//蛇的x坐标
    int[] snakeY = new int[500];//蛇的Y坐标
    int score;//游戏成绩
    boolean isStart;//游戏当前的状态,初始为暂停
    boolean isFail;//游戏失败状态

    //食物坐标
    int foodX;
    int foodY;
    Random random = new Random();//随机数
    Timer timer = new Timer(100,this);//定时器,100ms执行一次

这里对部分参数进行解释:

  1. 随机数,用作确定食物的位置,食物要随机分布,下面init()方法有提到。
  2. 定时器,定时刷新界面,前面已经讲到了贪吃蛇的移动象征面板的一次更新,使用定时器就可以定时更新一次面板,也就可以规定贪吃蛇的移动速度了

首先我们需要初始化属性的内容,不建议直接在定义时初始化,我这里采用了设计一个init()方法将这些参数初始化:

public void init(){
        length = 3;
        snakeX[0] = 100;   snakeY[0] = 100;//脑袋坐标
        snakeX[1] = 75;   snakeY[1] = 100;//第一个身体坐标
        snakeX[2] = 50;   snakeY[2] = 100;//第二个身体坐标
        score = 0;//积分初始为0
        direct = "R";//初始方向向右
        isStart = false;//初始为暂停
        isFail = false;//默认为不失败
        //食物随机分布在界面上
        foodX = 25 + 25 * random.nextInt(34);
        foodY = 75 + 25 * random.nextInt(24);
    }

静态图片我们这里继承JPanel类,重写了 protected void paintComponent(Graphics g)方法,该方法是用作绘制一次图片的,只要创建该类对象,即可进行一次绘制,自动调用一次这个方法,初始样式如下:

protected void paintComponent(Graphics g){
    super.paintComponent(g);//清屏
}

当我们在运行游戏开始时,即调用一次该方法,使之在游戏未动的时候对面板进行一次静态绘制。所以我们可以把我们想要画的初始界面的样子在这个时候先写好,譬如:

protected void paintComponent(Graphics g){
    super.paintComponent(g);//清屏
    setBackground(Color.white);

    //先绘制静态面板
    Data.header.paintIcon(this,g,25,11);//开头广告画上去
    g.fillRect(25,75,850,600);//默认游戏界面
//画积分
    g.setColor(Color.white);
    g.setFont(new Font("微软雅黑",Font.BOLD,18));
    g.drawString("长度:"+length,750,35);
    g.drawString("分数:"+score,750,55);

    g.setColor(Color.white);
    //设置字体
    g.setFont(new Font("微软雅黑",Font.BOLD,40));
    g.drawString("按下空格开始游戏",300,300);
}

这样就可以实现一个没有小蛇没有食物,但是基本框架都写好的页面。小蛇的静态图绘制只需要找好坐标,以上面类似绘制上广告的逻辑写即可:

Data.right.paintIcon(this,g,snakeX[0],snakeY[0]);//蛇头
for (int i = 1; i < length; i++) {
    Data.body.paintIcon(this,g,snakeX[i],snakeY[i]);//蛇身
}

这样我们就可以实现类似于开头这个图一样的页面了。

静态图绘制好了,我们需要实现动态,那么逻辑应该是怎样的呢?不妨把自己带入成一个游戏玩家:

我们按下空格可以开始,暂停游戏,按下上下左右可以变换贪吃蛇的运动方向,所以我们很明显,需要键盘监听器。

当贪吃蛇吃了食物,长度会变长;贪吃蛇也会按照它的方向保持移动;贪吃蛇吃到自己的身体,会游戏失败,很明显需要事件监听器。

所以要引入这些概念,我们很明显,调用两个监听器接口即可:

public class GamePanel extends JPanel implements KeyListener, ActionListener{
    @Override
    public void keyPressed(KeyEvent e){}//实现键盘监听

    @Override
    public void actionPerformed(ActionEvent e){}//实现事件监听

    //这两个不需要实现,只需要写上,不然会报错
    @Override
    public void keyTyped(KeyEvent e) {}
    @Override
    public void keyReleased(KeyEvent e) {}
}

键盘监听的逻辑很简单: 空格就是开始或者暂停,变换isStart变量; 上下左右就是小蛇移动,变换direct变量。

事件监听稍微麻烦一点:

  • 如果游戏是开始的情况,小蛇就要移动,要使小蛇移动很简单,就是让小蛇的后一节身体的位置变到前一节身体的位置:
for (int i = length - 1; i > 0; i--) {
    //后一节身体变成前一节身体的位置
    snakeX[i] = snakeX[i-1];
    snakeY[i] = snakeY[i-1];
}
  • 因为要上下左右动,所以监听方向,当向各种方向时,要变化蛇移动的距离和运动方向。考虑到该游戏的自行设计,设定为超出边界就从另一边出来,所以还要设计监听边界问题:
if (direct.equals("R")){//右移
    snakeX[0] = snakeX[0] + 25;
    //边界判断
    if (snakeX[0]>850){snakeX[0] = 25;}
}else if (direct.equals("L")){//左移
    snakeX[0] = snakeX[0] - 25;
    //边界判断
    if (snakeX[0]650){snakeY[0] = 75;}
}
  • 贪吃蛇要吃东西,所以需要一个蛇头碰到食物的情况:
if(snakeX[0] == foodX && snakeY[0] == foodY){
    length++;//长度+1
    score+=10;
    //然后再次随机生成食物
    foodX = 25 + 25 * random.nextInt(34);
    foodY = 75 + 25 * random.nextInt(24);
}
  • 失败事件,撞到自己就失败了:
for (int i = 1 ; i

监听的话已经实现,但是还是没有阐述如何动态,很简单,在监听器最后调用 repaint()方法即可,这个方法可以重新调用 paintComponent方法,也就是重新进行一次静态绘制,而 监听器通过改变了属性量,再进行一次静态绘制时,就已经不是原来的那张图了。而游戏中每时每刻都发生变化,这样我们每次绘制的面板都不一样,自然就能实现动态了。

当然,如果没有加入这些监听器是没用的,这里我们再重写以下无参构造:

public GamePanel(){
    init();
    //获得焦点和键盘事件
    setFocusable(true);
    addKeyListener(this);
    timer.start();
}

写到这里会发现,那个静态的绘制方法是不是过于简陋了,所以我们需要在静态方法里面加入一系列的 判断,因为每一次静态绘制,定义的参数量都可能发生了变化, 要想对他们的变化做出反应,就得针对他们不同情况的量做不同的绘制。这里在源码里面都有,不具体说了。

源码地址:

链接:百度网盘链接
提取码:xb58
备注:里面包含了静态资源,在staticFile文件夹内,如果想使用请更改Data数据类里面的路径。且该内容仅为源码,想测试效果请自行搭建项目复制粘贴。

Original: https://www.cnblogs.com/cola-pink/p/16005890.html
Author: 可乐加品客
Title: 贪吃蛇项目的制作

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/580565/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • SMBMS(超市订单管理系统)项目从零开始搭建

    如果需要完整的系统可以加我qq:1842329236 一、搭建一个maven web项目 新建一个maven,并且使用模板 maven的详细创建,及配置请看这篇文章https://…

    Java 2023年6月14日
    096
  • 基于数据库的代码自动生成工具,生成JavaBean、生成数据库文档、生成前后端代码等(v5.8.8版)

    TableGo v5.8.8版震撼发布,此次版本更新如下:1、新增两个扩展字段,用于生成自定义模板时使用。2、自定义模板新增模板目录,可以选择不同分类目录下的模板。3、自定义模板生…

    Java 2023年6月9日
    0101
  • 前端浅学之html

    浅学html 基础语法 标签 单标签 无属性 有属性 双标签 无属性 有属性 结构 表示当前是网页 头部信息 页面内容 举例 基础语法 好家伙 标题、水平线 语法 举例 嗯哼 搞笑…

    Java 2023年6月16日
    095
  • 数据库的多表查询

    我们知道,增删查改这几种操作在开发过程中不可或缺,下面重点介绍的是查询操作 在数据库中,80%的操作是通过查询完成的.在实际开发中能中,不可能只会用到一张表,多表查询在查询中起很大…

    Java 2023年6月8日
    089
  • 你见过哪些目瞪口呆的 Java 代码?

    自从毕业后,今年已经是我工作的第 8 个年头了,我甚至都快忘记了到底是哪年毕业的。 从出来,本人一直在做 Java 相关的工作,现在终于有时间坐下来,写一篇关于 Java 写法的一…

    Java 2023年5月29日
    084
  • 我又不是你的谁–java instanceof操作符用法揭秘

    背景故事 《曾经最美》是朱铭捷演唱的一首歌曲,由陈佳明填词,叶良俊谱曲,是电视剧《水晶之恋》的主题曲。歌曲时长4分28秒。 歌曲歌词: 看不穿你的眼睛 藏有多少悲和喜 像冰雪细腻又…

    Java 2023年5月29日
    0106
  • GBase 8t数据更新

    插入数据 插入元组 insert into &#x8868;&#x540D;(&#x5217;&#x540D;…) values (&#…

    Java 2023年6月9日
    070
  • MySQL系统变量和字符集

    书名《MySQL是怎样运行的:从根儿上理解MySQL》可自行百度 以下是知识点总结 重新认识Mysql MySQL是一个C/S架构的软件。 在Windows安装后首先注册成服务,然…

    Java 2023年6月16日
    071
  • linux 与 windows 挖门罗币总结

    比特币之前一直很火,初次了解的时候才2000RMB一枚..看不懂哇,错失良机…当然了,看得懂也不买不起..当时还是穷学生. 最近又一直看到黑客利用linux漏洞挖门罗币…

    Java 2023年6月16日
    083
  • 并发编程系列之如何正确使用线程池?

    并发编程系列博客 原文链接 并发编程系列之如何正确使用线程池?在上一章节的学习中,我们掌握了线程的基本知识,接着本博客会继续学习多线程中的线程池知识 1、线程是不是越多越好? 在学…

    Java 2023年5月30日
    090
  • spring事务的过程

    数据库:建立连接、开启事务、进行sql操作、成功提交、失败回滚 业务逻辑:准备工作(可以进行前置通知)、开启事务、事务操作、成功提交(可以后置通知)、失败回滚(异常通知) spri…

    Java 2023年6月9日
    077
  • java Script

    JavaScript JavaScript(简称”JS”)是一种具有函数优先的轻量级,解释型或即时编译型的高级编程语言,弱类型,脚本语言 三大部分 核心(E…

    Java 2023年6月6日
    092
  • idea 使用技巧之-多个project 启动idea时选择启动那个项目

    1File ->Settings-> Appearance & Behavior -> System Settings 取消勾选 Reopen proje…

    Java 2023年6月5日
    085
  • Java基础(标识符,数据类型,数据转换,变量)

    注释 Java中的注释有3种: 单行注释 // 多行注释 /**/ 文档注释 /***/ 注释不会被执行,是给我们写代码的人看的 书写注释是一个非常好的习惯 标识符 Java所有的…

    Java 2023年6月16日
    092
  • 推荐一款企业管理专用低代码工具,实现开发系统自由!

    之前分享过很多类型的文章,但是发现大家对低代码相关的文章,兴致还是比较高的,争议也很大。因为不少人认为低代码太草率,但真正的低代码不仅要负责生成代码,还要负责代码的维护,把它当做一…

    Java 2023年6月5日
    0127
  • @ConditionalOnMissingBean 如何实现覆盖第三方组件中的 Bean

    创建 olive-starter 项目对应的 pom.xml文件如下 <project xmlns="http://maven.apache.org/POM/4.0…

    Java 2023年6月7日
    080
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球