Java项目实战—JavaFX 贪吃蛇游戏设计与实现(附项目源代码地址)

news/2024/12/19 15:12:37/文章来源:https://www.cnblogs.com/java-note/p/18617303

该项目gitee地址:https://gitee.com/jflyfox/GameSnake.git

一、游戏概述

贪吃蛇是一款经典的街机游戏,玩家通过控制蛇的移动方向,使其吃到食物并不断增长身体长度,同时避免撞到墙壁或自身身体。本设计文档描述了一个使用JavaFX框架开发的贪吃蛇游戏的设计思路和实现细节。

二、游戏功能需求

  1. 游戏初始化
    • 游戏窗口具有固定大小(可配置)。
    • 蛇、食物和游戏信息在游戏开始时进行初始化并正确显示。
  2. 蛇的移动
    • 玩家可以使用方向键控制蛇的移动方向(上、下、左、右)。
    • 蛇以固定速度移动,每次移动一个单位长度。
    • 蛇不能直接掉头,必须先移动到下一个最小单位长度后才能改变方向。
  3. 食物生成
    • 食物随机出现在游戏场景中的空白位置,且位置是最小单位长度的整数倍。
    • 当蛇吃到食物后,食物消失并在新的位置重新生成。
  4. 身体增长
    • 每当蛇吃到食物,蛇的身体长度增加一个单位。
  5. 碰撞检测
    • 检测蛇头与墙壁的碰撞,若碰撞则蛇死亡,生命值减1,并重新初始化蛇的位置和身体长度(若生命值大于0)。
    • 检测蛇头与自身身体的碰撞,若碰撞则蛇死亡,生命值减1,并重新初始化蛇的位置和身体长度(若生命值大于0)。
  6. 游戏状态管理
    • 游戏具有开始、暂停、继续和结束等状态。
    • 在游戏过程中可以通过按键暂停和继续游戏。
    • 当蛇的生命值为0时,游戏结束,显示最终得分。
  7. 游戏信息显示
    • 在游戏界面上显示蛇的生命值、当前得分以及操作提示(如暂停键、重新开始键)。

三、系统架构设计

(一)总体架构

游戏采用MVC(Model-View-Controller)架构模式的变体,主要由以下几个模块组成:

  1. 模型(Model)
    • 包含游戏中的所有实体对象,如蛇(Snake)、蛇的身体(SnakeBody)和食物(Food)等。这些对象负责维护自身的状态和行为逻辑。
  2. 视图(View)
    • 由JavaFX的图形界面组件构成,包括游戏场景(GameScreen)和信息显示(Information)等部分。视图负责将模型中的数据以可视化的方式呈现给玩家。
  3. 控制(Controller)
    • 主要通过事件处理机制实现,包括键盘事件和鼠标事件的处理。控制模块负责接收玩家的输入,并根据输入更新模型和视图的状态。

(二)核心类设计

1. FFApplication

  • 类的职责
    • 作为整个应用程序的基础框架类,继承自Application,负责游戏窗口的创建和初始化过程。它提供了一个基本的模板,供子类实现具体的游戏逻辑。
  • 主要方法
    • start(Stage primaryStage):应用程序的启动入口点。在该方法中,首先调用before()方法进行一些前置初始化操作,然后创建GroupScene对象,接着调用after()方法进行后续的初始化操作,最后将Scene设置到Stage并显示出来。
    • before()after():这两个方法是留给子类重写的。before()方法通常用于设置游戏窗口的大小等初始化操作;after()方法用于在SceneGroup创建之后,进行一些添加游戏组件、注册事件监听器等操作。
    • showStage(Stage stage):设置Stage的场景并显示。同时提供了getScene()getRoot()方法,用于获取场景和根节点。

2. FFContants

  • 类的职责
    • 作为一个常量类,定义了游戏中使用的各种全局常量,如游戏屏幕的大小、最小单位长度等。这些常量在整个游戏中被广泛使用,通过集中定义可以方便地进行修改和维护。
  • 主要常量
    • WIDTHHEIGHT:定义了游戏屏幕的宽度和高度,默认值分别为800和600像素。
    • MIN_XMIN_Y:表示游戏中的最小单位长度,在水平和垂直方向上的默认值均为20像素。同时提供了init(int width, int height)方法,用于重新初始化屏幕大小的常量。

3. FFEvent

  • 类的职责
    • 定义了游戏中的基础事件接口,利用JDK8的默认方法特性,提供了一些默认的事件处理方法。这些方法为具体的事件处理类提供了一个统一的接口规范。
  • 主要方法
    • init():用于初始化事件的默认方法。在实际应用中,如果某个事件需要进行特定的初始化操作,可以重写该方法。
    • onKeyPressed(KeyEvent event)onKeyReleased(KeyEvent event)onMouseMoved(MouseEvent event):分别是按键按下、释放和鼠标移动的默认事件处理方法。具体的事件处理类可以根据需要重写这些方法来实现特定的业务逻辑。

4. FFObject

  • 类的职责
    • 作为游戏中的基础对象类,继承自FFEvent,它定义了所有游戏对象的通用属性和行为。所有的游戏实体对象(如蛇、食物等)都继承自该类,从而实现了代码的复用和统一的行为规范。
  • 主要属性
    • 包括位置属性(xPropertyyProperty)、大小属性(widthPropertyheightProperty)、更新状态属性(updateProperty)和可见性属性(visibleProperty)等。这些属性通过JavaFX的属性绑定机制进行管理,方便在对象状态发生变化时自动更新相关的视图。
  • 主要方法
    • init():用于初始化对象的默认方法。在该方法中,设置对象的可见性为true
    • draw(GraphicsContext gc)update():这两个方法是抽象方法,需要由子类具体实现。draw方法用于在图形上下文中绘制对象,update方法用于更新对象的状态。
    • 提供了各种属性的获取和设置方法,以及移动方法(moveX(double x)moveY(double y))和碰撞检测方法(isCollisionWith(FFObject baseObject))。这些方法为子类提供了基本的操作接口,用于实现对象的具体行为。

5. FFScreen

  • 类的职责
    • 作为游戏的基础展示类,继承自Canvas并实现FFEvent接口。它负责管理游戏中的所有可视对象,并通过动画机制实现对象的动态更新和展示。
  • 主要属性
    • List<FFObject> mObjects:用于存储游戏中的所有可视对象。通过这个列表,可以方便地对多个对象进行统一管理,如添加、删除和遍历操作。
    • Timeline timelineKeyFrame keyFrame:这两个对象构成了JavaFX的动画机制。Timeline定义了动画的时间轴,KeyFrame定义了动画的关键帧。通过设置合适的时间间隔和关键帧操作,可以实现对象的动态更新。
    • int duration:表示动画的时间间隔,单位为毫秒。默认值为10毫秒。
    • GameState mGameState:用于表示游戏的当前状态,包括游戏菜单、开始、继续、暂停、帮助、设置和退出等状态。通过这个状态变量,可以方便地控制游戏的流程和行为。
  • 主要方法
    • 构造函数:在构造函数中,首先调用父类的构造函数创建Canvas对象,并设置其大小。然后初始化时间轴(initTimeLine()),为动画的运行做好准备。
    • initEvents():用于初始化游戏中的键盘和鼠标事件。在该方法中,分别为Scene的按键按下、释放和鼠标移动事件注册监听器,并将事件转发给相应的对象进行处理。
    • 针对按键按下、释放和鼠标移动的事件处理方法(onKeyPressed(KeyEvent event)onKeyReleased(KeyEvent event)onMouseMoved(MouseEvent event)):这些方法会遍历mObjects列表中的所有对象,并调用对象自身的相应事件处理方法。这样可以实现对多个对象的统一事件处理。
    • addObject(FFObject baseObject)removeObject(FFObject baseObject)removeObjectAtIndex(int index):用于管理mObjects列表中的对象。通过这些方法,可以方便地向游戏场景中添加、删除对象。
    • draw(GraphicsContext gc):用于绘制游戏场景中的所有可视对象。在绘制之前,首先清除画布(gc.clearRect(0, 0, getWidth(), getHeight())),然后遍历mObjects列表,对于可见的对象调用其draw方法进行绘制。
    • update():用于更新游戏场景中的所有可视对象。在更新过程中,遍历mObjects列表,对于可更新的对象(通过isUpdate()方法判断)调用其update方法进行更新。
    • 时间轴相关的方法(initTimeLine()start()pause()stop()):这些方法用于控制动画的运行状态。initTimeLine()方法用于初始化时间轴和关键帧;start()方法用于启动动画;pause()方法用于暂停动画;stop()方法用于停止动画。

(三)游戏实体类设计

1. Snake

  • 类的职责
    • 表示贪吃蛇对象,是游戏的核心实体之一。它负责维护蛇的各种属性,如位置、方向、长度、速度、生命值和得分等,并实现蛇的移动、吃食物、碰撞检测等行为逻辑。
  • 主要属性
    • AtomicInteger score:用于记录蛇的得分。使用AtomicInteger类型是为了保证在多线程环境下得分的正确更新。
    • Color snakeColor:表示蛇的颜色。
    • KeyCode keyCode:用于记录蛇的当前移动方向。
    • KeyCode tmpKeyCode:用于记录蛇的临时移动方向。在蛇移动到下一个最小单位长度之前,新的方向会先存储在tmpKeyCode中,待满足条件后再更新到keyCode中。
    • int speed:表示蛇的移动速度,即每次移动的单位长度。
    • int hp:表示蛇的生命值。当蛇撞到墙壁或自身身体时,生命值会减少。
    • int length:表示蛇的身体长度,初始值为默认长度(DEFAULT_LENGTH)。
  • 主要方法
    • init():用于初始化蛇的所有属性。在初始化过程中,设置得分、大小、方向、颜色、速度、生命值和长度等属性的值,并将蛇的位置设置在游戏场景的左上角((0, 0))。
    • draw(GraphicsContext gc):用于在图形上下文中绘制蛇的头部。根据蛇的颜色(snakeColor),使用gc.fillRect()方法绘制一个矩形表示蛇头。
    • update():用于更新蛇的位置和方向。根据当前的移动方向(keyCode),通过moveX()moveY()方法移动蛇的位置。同时,在移动过程中,判断是否满足改变方向的条件(即移动到下一个最小单位长度且新方向与当前方向不冲突),如果满足条件则更新keyCode的值。另外,还需要判断蛇是否撞到墙壁或自身身体,如果发生碰撞则调用death()方法处理。
    • death():用于处理蛇死亡的情况。当蛇死亡时,将蛇的位置重置为游戏场景的左上角((0, 0)),方向重置为初始方向(KeyCode.RIGHT),身体长度重置为默认长度(DEFAULT_LENGTH),并减少生命值(reduceHp())。
    • onKeyPressed(KeyEvent event):用于处理按键按下事件。当玩家按下方向键时,首先获取按下的键码(tmpCode),然后判断新方向是否与当前方向冲突(即是否为反方向),如果不冲突且是有效的方向键(上、下、左、右),则将新方向存储在tmpKeyCode中。
    • score()addScore()getHp()reduceHp()getLength()addLength()getSnakeColor():这些方法分别用于获取和修改蛇的得分、生命值、长度和颜色等属性。其中,addScore()方法通过AtomicIntegerincrementAndGet()方法实现得分的原子性增加。

2. SnakeBody

  • 类的职责
    • 表示贪吃蛇的身体部分,与Snake类紧密相关。它负责维护蛇身体的位置列表,并实现身体的绘制、更新和碰撞检测等行为逻辑。
  • 主要属性
    • Snake snake:用于关联对应的蛇对象。通过这个关联,可以获取蛇的相关属性和方法,如蛇的位置、长度等。
    • int length:用于记录蛇身体的当前长度。这个长度会随着蛇吃到食物而增加。
    • LinkedList<Point> list:用于存储蛇身体各个部分的坐标。Point是JavaFX中的一个类,表示二维空间中的一个点。
  • 主要方法
    • init():用于初始化蛇身体的属性。在初始化过程中,首先调用父类的init()方法,然后设置蛇身体的长度为蛇的当前长度(snake.getLength()),并清空位置列表(list.clear())。接着,通过循环根据蛇的位置和长度计算出身体各个部分的初始坐标,并添加到位置列表中。
    • draw(GraphicsContext gc):用于在图形上下文中绘制蛇的身体。如果蛇的身体长度小于等于1,则不进行绘制。在绘制过程中,首先获取位置列表中的第一个点(firstPoi),判断蛇是否移动了一个身位(通过比较第一个点与蛇头的位置关系),如果移动了则进行位置更新。更新位置时,添加一个新的头部坐标到位置列表的开头(list.addFirst(poi)),如果没有吃到食物则删除位置列表的最后一个元素(list.removeLast())。然后,根据位置列表中的坐标,使用gc.fillRect()方法绘制每个身体部分(包括第一个点)。
    • update():用于更新蛇身体的状态。如果蛇身体不可见,则调用init()方法重新初始化并设置为可见。
    • isCollisionWith(FFObject baseObject):用于检测蛇身体是否与其他对象发生碰撞。在检测过程中,遍历位置列表中的所有点(除了第一个点,表示蛇头),通过isCollisionWith(double x, double y, FFObject baseObject)方法检测每个点是否与其他对象发生碰撞,如果有任何一个点发生碰撞则返回true

3. Food

  • 类的职责
    • 表示食物对象,是游戏中的另一个核心实体。它负责随机生成食物的位置,并实现食物的绘制和更新等行为逻辑。
  • 主要属性
    • SecureRandom random:用于生成随机数。通过这个随机数生成器,可以在游戏场景中随机生成食物的位置。
  • 主要方法
    • init():用于初始化食物的属性。在初始化过程中,首先调用父类的init()方法,然后设置食物的大小为最小单位长度(FFContants.MIN_XFFContants.MIN_Y),并通过createRandomFood()方法随机生成食物的位置。
    • draw(GraphicsContext gc):用于在图形上下文中绘制食物。将食物绘制为一个红色的圆形(gc.fillOval()),其位置和大小由食物的属性决定。
    • update():用于更新食物的状态。如果食物不可见,则调用createRandomFood()方法重新生成食物的位置,并设置为可见。
    • createRandomFood():用于随机生成食物的位置。在生成过程中,首先通过random.nextInt()方法分别在水平和垂直方向上生成一个随机数,这个随机数的范围是根据游戏屏幕大小和最小单位长度计算出来的,保证生成的位置是最小单位长度的整数倍。然后将生成的位置设置为食物的位置(setX(x)setY(y))。

(四)游戏界面类设计

1. GameScreen

  • 类的职责
    • 作为游戏的主界面类,负责管理游戏场景中的所有对象和游戏流程。它集成了蛇、蛇身体、食物和信息显示等各个部分,通过调用它们的方法实现游戏的运行和交互。
  • 主要属性
    • Information info:用于显示游戏信息的对象。通过这个对象,可以获取和设置游戏的生命值、得分等信息,并在界面上显示出来。
    • Snake snakeSnakeBody snakeBodyFood food:分别表示游戏中的蛇、蛇身体和食物对象。这些对象是游戏的核心实体,通过在GameScreen中进行管理和协调,实现游戏的正常运行

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/855410.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于QT+MQTT的实时视频监控

MQTT(Message Queuing Telemetry Transport)是一种基于发布/订阅模式的轻量级通信协议,广泛应用于物联网领域。它允许设备通过极少的代码和有限的带宽实现实时可靠的消息服务。MQTT协议的核心在于其三部分组成的控制报文:固定报头、可变报头和有效载荷。mqtt中的一些名词解…

在 K8S 中创建 Pod 是如何使用到 GPU 的:nvidia device plugin 源码分析

本文主要分析了在 K8s 中创建一个 Pod 并申请 GPU 资源,最终该 Pod 时怎么能够使用 GPU 的,具体的实现原理,以及 device plugin、nvidia-container-toolkit 相关源码分析。1.概述 在 两篇文章中分别分享了在不同环境如何使用 GPU,以及在 k8s 中使用 GPU Operator 来加速部…

unity 协程

协程 异步执行 必须带关键字 yield return 0 ;程序暂时挂起

修改网站统计图标的位置,网站统计图标位置调整指南

修改网站统计图标的位置通常涉及编辑网站的HTML和CSS文件。以下是详细的步骤:确定修改需求:明确需要将统计图标移动到的具体位置。备份网站文件:在进行任何修改之前,建议先备份网站的所有文件。连接到FTP服务器:使用FTP客户端(如FileZilla、WinSCP等)连接到你的服务器。…

C语言浮点数相等判定

等价关系 按照离散数学的等价关系叙述,集合 \(X\) 上的关系 \(R \subset (X, X)\) 如果满足反身性: \((x, x) \in R, \forall x \in X\),自己等于自己 对称性: 如果 \((x, y) \in R\),则 \((y, x) \in R\),我等于你,则你也等于我 传递性: 如果 \((x, y) \in R\) 且 \((y, …

怎么修改网站admin密码,如何安全地修改网站后台管理系统的admin密码,提升安全性,防止未授权访问

修改网站后台管理系统的admin密码是确保网站安全的重要措施。以下是详细的修改步骤:登录后台管理系统:使用当前的admin账户登录网站后台管理系统。 确保使用的是最新的浏览器,以获得最佳的用户体验。进入用户管理页面:在后台管理系统中,找到“用户管理”或“管理员管理”选…

PbootCMS 织梦支付宝接口常见错误

错误代码 ILLEGAL_PARTNER:更新 PARTNER 值和安全校检码。 确认 PARTNER 值和安全校检码对应且有效。 确认 PARTNER 开通了所需的服务。错误代码 HAS_NO_PRIVILEGE:登录签约的支付宝账号,查询接口服务类型和合同生效时间。 确认服务名称、合同生效时间、合作者身份ID和校验码…

帝国CMS调用标题分类灵动标签

[e:loop={1,5,0,0}] 【<a href="<?=sys_ReturnBqInfoTypeUrl($bqr[ttid])?>"><?=class_tr[$bqr[ttid]][tname]?></a>】 <a href="<?=$bqsr[titleurl]?>" target="_blank"><?=$bqr[title]?>&l…

旅游开发团队协作,什么办公软件能增进默契?

冬季旅游市场具有独特的魅力与挑战,对于旅游公司而言,选择合适的团队协作办公软件至关重要。这些软件不仅要满足日常业务需求,更要契合冬季旅游的特殊情境,如应对旅游高峰期的高效协作、保障寒冷天气下旅游行程的顺利进行等。对于 MBTI 中的 J 人来说,有序、高效且可视化的…

SpringCodel微服务

SpringCodel微服务 docker启动命令: systemctl start docker 启动docker systemctl status docker 查看docker状态 systemctl enable docker 设置开机自启设置容器开机自启 docker update status=aways 容器名docker ps 格式化输出容器内容 (1)--format &qu…

验证云通行证失败, 请求连接无效

新合新公有云登录协同开发平台登录时提示"验证云通行证失败, 请求连接无效", 其他私有环境都正常 解决方案: 需要通过金蝶引导程序更新一下BOS程序

给我2分钟,保证教会你在Vue3中实现一个定高的虚拟列表

前言 虚拟列表对于大部分一线开发同学来说是一点都不陌生的东西了,有的同学是直接使用第三方组件。但是面试时如果你简历上面写了虚拟列表,却给面试官说是通过三方组件实现的,此时空气可能都凝固了。所以这篇文章欧阳将会教你2分钟内实现一个定高的虚拟列表,至于不定高的虚…