JavaFX深度实践:从零构建高级打地鼠游戏(含多物品与反馈机制)

news2025/4/23 10:01:03

大家好!经典的“打地鼠”游戏是许多人童年的回忆,也是学习 GUI 编程一个非常好的切入点。但仅仅是“地鼠出来就打”未免有些单调。今天,我们来点不一样的——用 JavaFX 打造一个高级版的打地鼠游戏!在这个版本中,洞里钻出来的可不仅仅是普通地鼠,还可能有炸弹奖励品,你需要眼疾手快,准确判断,这无疑增加了游戏的挑战性和趣味性。

这篇文章将带你深入了解整个开发过程,从界面布局到核心逻辑,从事件处理到动画反馈,全面解析如何利用 JavaFX 的特性构建一个功能丰富、交互性强的小游戏。无论你是想系统学习 JavaFX,还是寻找一个能体现综合能力的实战项目,相信本文都能给你带来启发。

高级版特性一览:

  • 多种物品: 普通地鼠(得分)、炸弹(扣分+惩罚)、奖励星星(高分)。
  • 随机性: 物品类型、出现位置、出现时间、停留时间都包含随机元素。
  • 即时反馈: 清晰的得分/扣分提示、时间倒计时、击中效果(背景闪烁)。
  • 游戏核心循环: 使用 JavaFX 动画 API (Timeline, PauseTransition) 精确控制游戏节奏。

一、 设计核心:拆解游戏机制与界面布局

动手编码前,我们先规划好游戏的骨架。

核心游戏循环:

  1. 开始: 玩家点击“开始游戏”,计时器启动,游戏状态激活。
  2. 物品生成: itemSpawner 计时器以随机间隔触发,在随机可用的洞 (ItemHole) 中,根据预设概率 (BOMB_PROBABILITY, BONUS_PROBABILITY) 决定生成地鼠、炸弹还是奖励,并调用该洞的 showItem() 方法。
  3. 物品显示与消失: showItem() 显示物品,并启动一个随机时长的 hideTimer (PauseTransition)。如果玩家未在时间内点击,hideTimer 结束时自动调用 hideItem() 使物品消失。
  4. 玩家交互 (handleWhack): 玩家点击某个洞 (StackPane)。
    • 检查游戏是否进行中 (gameActive) 且是否接受输入 (acceptingInput)。
    • 检查该洞当前是否有可见物品 (itemVisible)。
    • 如果满足条件,根据 currentItemType 判断击中的是何物:
      • 地鼠: 加分,显示得分反馈,洞背景闪烁,调用 hideItem()
      • 炸弹: 扣分,显示扣分反馈,洞背景闪烁(红色),触发 triggerBombPenalty()(例如暂时禁用输入并使屏幕变暗),调用 hideItem()
      • 奖励: 加高分,显示奖励反馈,洞背景闪烁(金色),调用 hideItem()
    • 更新总分显示。
  5. 时间流逝: gameTimer 计时器每秒触发一次,更新剩余时间显示。
  6. 结束:timeLeft 减到 0 时,停止所有计时器,禁用输入,显示最终得分。玩家可点击按钮重新开始。

界面布局 (BorderPane):

  • 顶部 (Top): 使用 VBox 垂直堆叠 scoreLabel, timeLabel 和新增的 feedbackLabel(用于显示“打中了+10”、“炸弹!-25”等即时消息)。
  • 中部 (Center): GridPane (gameGrid) 容纳 3x3 的地鼠洞。每个洞本身是一个 ItemHole 对象,其 UI 根节点是 StackPane
  • 底部 (Bottom): HBox 放置“开始/停止游戏”按钮 (startButton)。
    在这里插入图片描述

二、 JavaFX 实现技术深潜

1. 封装的艺术:ItemHole 内部类

将每个“洞”及其内部逻辑封装成一个内部类 ItemHole 是本次设计的关键之一。这样做的好处是:

  • 高内聚: 每个洞自己管理自己的状态(是否有物品 itemVisible,是什么物品 currentItemType,物品图形 itemShape)和行为(showItem, hideItem, handleWhack, flashBackground)。
  • 易于管理: 主类只需要维护一个 List<ItemHole>,方便遍历和随机选择。
  • UI 结构: 使用 StackPane 作为洞的根节点,天然支持将洞的背景(通过 setStyle 设置背景色和圆角)和物品图形 (itemShape) 叠加显示。
private class ItemHole {
    StackPane pane; // 洞的 UI 容器
    Shape itemShape; // 物品图形 (通用 Shape)
    ItemType currentItemType = null; // 当前物品类型
    boolean itemVisible = false;
    PauseTransition hideTimer; // 自动隐藏计时器
    PauseTransition flashTimer; // 背景闪烁计时器

    ItemHole() {
        // ... (初始化 pane 样式, itemShape) ...
        pane.setOnMouseClicked(event -> { // 在 pane 上监听点击
            if (gameActive && acceptingInput && itemVisible) {
                handleWhack();
            }
        });
        pane.getChildren().add(itemShape);
    }

    void showItem(ItemType type) {
        // ... (设置 itemVisible, currentItemType, 根据 type 设置 itemShape 颜色/形状, 启动 hideTimer) ...
    }
    void hideItem(boolean whackOccurred) {
        // ... (停止 hideTimer, 设置 itemVisible=false, 隐藏 itemShape, currentItemType=null) ...
    }
    void handleWhack() {
        // ... (根据 currentItemType 加减分, setFeedback, flashBackground, 调用 hideItem(true)) ...
    }
    void flashBackground(Color flashColor) {
        // ... (停止旧 flashTimer, 修改 pane 背景色, 启动新 flashTimer 恢复背景色) ...
    }
}

注意: 点击事件监听器设置在 StackPane 上而不是 itemShape 上,这样即使物品图形没有完全填满洞,点击洞的任何位置都能触发(只要物品是可见的)。itemShape.setMouseTransparent(true) 确保点击能穿透图形本身到达 StackPane

2. 精准的时间控制:TimelinePauseTransition

JavaFX 的动画 API 在这里大放异彩:

  • gameTimer (Timeline): 实现游戏主倒计时。new KeyFrame(Duration.seconds(1), ...) 定义了每秒执行一次的操作(timeLeft--, 更新UI)。setCycleCount(Timeline.INDEFINITE) 让它一直运行直到被 stop()
  • itemSpawner (Timeline): 控制物品的生成节奏。它的 KeyFrame 持续时间不是固定的,而是通过 rateProperty().bind() 绑定到一个动态计算的值上,引入了 random.nextDouble(),使得每次生成的间隔在 BASE_APPEAR_INTERVAL_SECONDS 附近随机波动,增加了不可预测性。
    // 动态调整 Timeline 的速率来实现随机间隔
    itemSpawner.rateProperty().bind(
        javafx.beans.binding.Bindings.createDoubleBinding(
            () -> 1.0 / (BASE_APPEAR_INTERVAL_SECONDS * (0.7 + random.nextDouble() * 0.6)), // 0.7 到 1.3 倍基础间隔
            gameActiveProperty() // 绑定到游戏状态属性
        )
    );
    
  • hideTimer (PauseTransition): 用于物品出现后,等待一段随机时间自动消失。PauseTransition 非常适合这种“延迟执行一次”的场景。
  • flashTimer (PauseTransition): 用于实现背景闪烁的短暂效果。在 flashBackground 中启动,延迟一小段时间后恢复 pane 的原始背景样式。
  • penaltyTimer (PauseTransition): 用于实现炸弹惩罚的持续时间。
3. 概率与随机性

游戏的趣味性很大程度上来源于随机性:

  • 出现位置 (popRandomItem):itemHoles 列表中筛选出当前没有物品的洞 (!itemVisible),然后从中随机选择一个。
  • 出现物品类型 (chooseRandomItemType): 根据 BOMB_PROBABILITYBONUS_PROBABILITY 使用 random.nextDouble() 决定本次生成地鼠、炸弹还是奖励。
  • 出现间隔: 如上所述,通过动态调整 itemSpawnerrate 实现。
  • 停留时间:showItem 中,hideTimer 的持续时间是在 MIN_ITEM_UP_TIME_SECONDSMAX_ITEM_UP_TIME_SECONDS 之间随机生成的。
4. 即时反馈的重要性

良好的反馈能极大提升游戏体验:

  • 得分/时间更新: updateScoreLabel()updateTimeLabel() 实时更新。
  • 文字反馈 (feedbackLabel, setFeedback): 当玩家打中特定物品或游戏状态改变时,在 feedbackLabel 短暂显示提示信息,并使用不同颜色区分(绿:得分,红:扣分,金:奖励,蓝:状态)。setFeedback 还内置了一个 PauseTransition 来自动清除过时的反馈。
  • 视觉反馈 (flashBackground): 击中物品时,对应洞的背景短暂闪烁特定颜色,给玩家一个强烈的视觉确认。
  • 惩罚反馈 (triggerBombPenalty): 点击炸弹后,通过 ColorAdjust 效果使整个游戏区域变暗,并暂时禁用输入 (acceptingInput = false),提供明确的负面反馈。
5. 状态同步与控制流

gameActiveacceptingInput 这两个布尔标志变量对于控制游戏流程至关重要:

  • gameActive 控制游戏的主计时器和物品生成器是否运行,以及是否处理大多数点击事件。
  • acceptingInput 专门用于炸弹惩罚,它可以在 gameActivetrue 的情况下暂时阻止玩家的有效点击。

所有事件处理器(按钮点击、洞点击、计时器触发)都需要首先检查相关的状态变量,确保在正确的时机执行正确的操作。

四、 总结与扩展思考

通过实现这个高级版的“打地鼠”游戏,我们深入运用了 JavaFX 的布局、事件处理、动画计时器、自定义绘图(虽然本例简化为设置颜色,但可以扩展)以及状态管理等关键技术。内部类 ItemHole 的设计体现了良好的封装思想。随机性、多种物品和丰富的反馈机制共同提升了游戏的可玩性。

当然,这个游戏还可以继续打磨:

  1. 更丰富的视觉效果: 使用图片代替纯色圆形作为地鼠/炸弹/奖励;添加更复杂的动画(如地鼠探头、缩回的动画)。
  2. 音效: 为出现、击中(不同物品)、错过、游戏结束等添加音效。
  3. 难度曲线: 实现动态难度,例如随着时间推移,物品出现间隔缩短、停留时间减少、炸弹概率增加等。
  4. 高分榜: 记录并显示玩家的最高得分。
  5. 自定义设置: 允许玩家选择网格大小、游戏时长等。

希望这篇结合了代码实践和技术解析的文章,能让你对如何使用 JavaFX 构建一个交互性强、功能复杂的应用有更深的理解。动手实践是掌握技术的最好方式,现在就尝试在这个基础上添加你自己的创意吧!


附注: 上述代码片段是说明性的,完整的可运行代码文前资源文件中的java完整示例。确保你的开发环境已正确配置 JavaFX。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python 简介与入门

目录 一、Python 初识 1、Python 的优势 2、Python 的特性 3、Python 的应用领域 二、Linux 环境中安装 Python 1、下载 Python3.11.6 2、安装依赖包 3、解压 Python 压缩包 4、安装 Python 5、编译及安装 6、建立软链接 7、测试 Python3 运行 8、设置国内 pip 更…

理解RAG第六部分:有效的检索优化

在RAG系统中&#xff0c;识别相关上下文的检索器组件的性能与语言模型在生成有效响应方面的性能同样重要&#xff0c;甚至更为重要。因此&#xff0c;一些改进RAG系统的努力将重点放在优化检索过程上。 从检索方面提高RAG系统性能的一些常见方法。通过实施高级检索技术&#x…

实训Day-2 流量分析与安全杂项

目录 实训Day-2-1流量分析实战 实训目的 实训任务1 SYN半链接攻击流量分析 实训任务2 SQL注入攻击流量分析一 实训任务3 SQL注入攻击流量分析二 实训任务4 Web入侵溯源一 实训任务5 Web入侵溯源二 ​编辑 实训Day-2-1安全杂项实战 实训目的 实训任务1 流量分析 FTP…

几种电气绝缘类型

1. 基本绝缘 1.1 绝缘等级 1.2 I类设备 2. 附加绝缘 3. 双重绝缘 4. 加强绝缘 5. 功能性绝缘 1. 基本绝缘 用于防止触及带电部件的初级保护,该防护是由绝缘材料完成的 基本绝缘的目的在于为防电击提供一个基本的保护,以避免触电的危险,不过此类绝缘只能保证正常状态下…

char32_t、char16_t、wchar_t 用于 c++ 语言里存储 unicode 编码的字符,给出它们的具体定义

&#xff08;1&#xff09; #include <iostream> #include <string>int main() { std::u16string s u"C11 引入 char16_t"; // 定义 UTF-16 字符串for (char16_t c : s) // 遍历输出每个 char16_t 的值std::cout << std::hex << (…

Java Set/List 知识点 Java面试 基础面试题

Java Set/List 知识点 Set与List区别 List 有序、值可重复,内部数据结构 Obejct[ ] 数组Set 无序、值不重复,内部数据结构 HashMap keyobject value固定new Object() ArrayList 有序存储元素允许元素重复&#xff0c;允许存储 null 值支持动态扩容非线程安全 HashSet、LinkedHa…

Oracle Database Resident Connection Pooling (DRCP) 白皮书阅读笔记

本文为“Extreme Oracle Database Connection Scalability with Database Resident Connection Pooling (DRCP)”的中文翻译加阅读笔记。觉得是重点的就用粗体表示了。 白皮书版本为March 2025, Version 3.3&#xff0c;副标题为&#xff1a;Optimizing Oracle Database resou…

FastAPI WebSocket 聊天应用详细教程

项目简介 这是一个基于 FastAPI 和 WebSocket 实现的实时聊天应用&#xff0c;支持一对一聊天、离线消息存储等功能。 技术栈 后端&#xff1a;FastAPI (Python)前端&#xff1a;HTML、JavaScript、CSS通信&#xff1a;WebSocket认证&#xff1a;简单的 token 认证 项目结构…

vue3+canvas裁剪框样式【前端】

目录 canvas绘制裁剪框&#xff1a;拖拽改变框的大小&#xff1a;圆圈样式&#xff1a;方块样式&#xff1a; canvas绘制裁剪框&#xff1a; // 绘制裁剪框 const drawCropRect (ctx: CanvasRenderingContext2D): void > {if (cropRect.value.width > 0 && crop…

软件功能测试和非功能测试有什么区别和联系?

软件测试是保障软件质量的核心环节&#xff0c;而软件功能测试和非功能测试作为测试领域的两大重要组成部分&#xff0c;承担着不同但又相互关联的职责。 软件功能测试指的是通过验证软件系统的各项功能是否按照需求规格说明书来正确实现&#xff0c;确保软件的功能和业务流程…

10_C++入门案例习题: 结构体案例

案例描述 学校正在做毕设项目&#xff0c;每名老师带领5个学生&#xff0c;总共有3名老师&#xff0c;需求如下 设计学生和老师的结构体&#xff0c;其中在老师的结构体中&#xff0c;有老师姓名和一个存放5名学生的数组作为成员 学生的成员有姓名、考试分数&#xff0c; 创建…

快速定位达梦缓存的执行计划并清理

开发告诉你一个sql慢&#xff0c;你想看看缓存中执行计划时&#xff0c;怎么精准快速定位&#xff1f; 可能一般人通过文本内容模糊搜索 select cache_item, substr(sqlstr,1,60)stmt from v$cachepln where sqlstr like %YOUR SQL STRING%; 搜出来的内容比较多&#xff0c;研…

若依、vben-admin、三维可视化

对三维可视化&#xff0c;包括cesium、模型加载、GIS有关的项目和技术都可以私信&#xff0c;包括基础数据后台管理系统的搭建和配置

LLMs可在2位精度下保持高准确率

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

爆改 toxml 组件 支持数据双向绑定 解决数据刷新问题

GGGGGGGGGGGGGGGGGithub地址自行研究 sbfkcel/towxml: 微信小程序HTML、Markdown渲染库https://github.com/sbfkcel/towxml原组件是以导入数据渲染信息为目的、本文以AI数据返回小程序为模拟效果演示 默认情况只在ready 环节进行渲染静态资源 1、对传入数据容器的位置做处理 …

Unreal如何使用后处理材质实现一个黑屏渐变效果

文章目录 前言相机后期处理材质创建材质相机设置动态修改FadeAlpha参数使用示例最后前言 UE5 开发VR ,如何通过PostProcess轻松实现黑屏渐变效果 最简单的办法,其实是使用一个半球形模型,遮挡住相机,然后控制这个半球形遮罩的颜色透明度,至少Unity中默认的Tunneling是这么…

DB-GPT支持mcp协议配置说明

简介 在 DB-GPT 中使用 MCP&#xff08;Model Context Protocol&#xff09;协议&#xff0c;主要通过配置 MCP 服务器和智能体协作实现外部工具集成与数据交互。 开启mcp服务&#xff0c;这里以网页抓取为例 npx -y supergateway --stdio "uvx mcp-server-fetch" …

CoT-Drive:利用 LLM 和思维链提示实现自动驾驶的高效运动预测

25年3月来自澳门大学和 MIT 的论文“CoT-Drive: Efficient Motion Forecasting for Autonomous Driving with LLMs and Chain-of-Thought Prompting”。 准确的运动预测对于安全的自动驾驶 (AD) 至关重要。本研究提出 CoT-Drive&#xff0c;这是一种利用大语言模型 (LLM) 和思…

Flowable7.x学习笔记(十)分页查询已部署 BPMN XML 流程

前言 上一篇文章我们已经完成了流程的部署功能&#xff0c;那么下一步就是要激活流程了&#xff0c;但是我们要需要明确的指定具体要激活部署后的哪一条流程&#xff0c;所以我们先把已部署的基础信息以及具体定义信息分页查询出来&#xff0c;本文先把基础代码生成以及完成分页…

Office文档图片批量提取工具

Office.Files.Images 是一款专注于从 Word、Excel、PPT 等 Office 文档中批量提取图片的轻量级工具&#xff0c;支持 .docx、.xlsx、.pptx 格式文件。该软件体积仅 ‌343KB‌&#xff0c;无需安装即可运行&#xff0c;通过拖拽操作实现快速解析与导出&#xff0c;尤其适合需批量…