0

0

如何通过 KeyEvent 实现空格键长按下的定时射击(每2秒发射一发子弹)

霞舞

霞舞

发布时间:2026-01-13 15:43:02

|

161人浏览过

|

来源于php中文网

原创

如何通过 KeyEvent 实现空格键长按下的定时射击(每2秒发射一发子弹)

本文讲解如何利用 keyevent 的 key_pressed/key_released 事件替代默认的 key_typed 行为,结合定时器实现“按住空格键时每2秒发射一枚子弹”的精准控制逻辑,避免连续触发导致的子弹堆积问题。

在 JavaFX 或 AWT/Swing 游戏开发中,直接监听 KeyEvent.KEY_TYPED(即 k.getEventType() == KeyEvent.KEY_TYPED)来响应空格键会导致不可控的重复触发——这是因为操作系统键盘重复输入机制会根据系统设置(如“按键重复延迟”和“重复速率”)自动发送大量 KEY_TYPED 事件,与你的游戏逻辑完全脱节。而 KEY_PRESSED 和 KEY_RELEASED 是底层硬件级事件,仅在按键按下和松开瞬间各触发一次,可控性强,是实现“长按触发周期行为”的正确入口。

✅ 正确做法:

  • 在 KEY_PRESSED 事件中启动一个单次调度的定时任务(如 ScheduledExecutorService 或 Timer),以固定间隔(如 2000ms)调用 newBullet();
  • 在 KEY_RELEASED 事件中取消该任务,防止松开后继续发射;
  • 彻底忽略 KEY_TYPED,不在 move() 中处理空格的 KEY_TYPED。

以下是重构后的控制器关键代码(使用 ScheduledExecutorService 更推荐,线程安全且易于管理):

怪兽AI数字人
怪兽AI数字人

数字人短视频创作,数字人直播,实时驱动数字人

下载
// 在控制器类中声明
private ScheduledExecutorService shootScheduler = null;
private ScheduledFuture shootTask = null;

private void move(KeyEvent k) {
    switch (k.getEventType()) {
        case KeyEvent.KEY_PRESSED:
            switch (k.getCode()) {
                case LEFT:  this.model.spaceshipLeft(); break;
                case RIGHT: this.model.spaceshipRight(); break;
                case UP:    this.model.spaceshipUp();    break;
                case DOWN:  this.model.spaceshipDown();  break;
                case SPACE:
                    if (shootScheduler == null) {
                        shootScheduler = Executors.newSingleThreadScheduledExecutor(
                            r -> { Thread t = new Thread(r); t.setDaemon(true); return t; }
                        );
                    }
                    // 每2秒发射一发,初始延迟0ms(立即发射第一发)
                    shootTask = shootScheduler.scheduleAtFixedRate(
                        () -> Platform.runLater(() -> {
                            this.model.newBullet();
                            this.update(); // 确保视图同步刷新
                        }),
                        0, 2000, TimeUnit.MILLISECONDS
                    );
                    break;
            }
            break;

        case KeyEvent.KEY_RELEASED:
            if (k.getCode() == KeyCode.SPACE && shootTask != null) {
                shootTask.cancel(true);
                shootTask = null;
                // 可选:清空可能正在执行中的任务(因 cancel(true) 已中断)
            }
            break;
    }
    view.update();
}

⚠️ 注意事项:

  • 不要复用 Timer 实例多次调用 scheduleAtFixedRate:你原代码中每次 shoot() 都新建 ShootBullet 并调度,会导致多个并发定时器叠加,子弹频率指数级增长;
  • ShootBullet 类当前设计存在严重缺陷:其 run() 方法内含无限 while(true) 循环 + 手动 tick 调度,不仅与 JavaFX 线程模型冲突(Platform.runLater 不能在非 FX 线程中频繁滥用),还会阻塞 Timer 线程,造成资源泄漏;应彻底移除;
  • 使用 ScheduledExecutorService + Platform.runLater 是 JavaFX 应用的标准实践,确保 UI 更新始终在 JavaFX Application Thread 执行;
  • 若需支持多键同时按压(如方向+空格),上述逻辑依然健壮,因 KEY_PRESSED/RELEASED 事件天然支持组合键。

总结:通过区分 KeyEvent 类型、合理启停周期任务,并规避系统级重复输入干扰,即可优雅实现“按住即规律发射”的游戏交互体验。核心原则是——用事件状态(按下/释放)控制定时器生命周期,而非用事件流驱动发射逻辑。

相关专题

更多
while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

84

2023.09.25

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

386

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

569

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

480

2023.08.10

Java 并发编程高级实践
Java 并发编程高级实践

本专题深入讲解 Java 在高并发开发中的核心技术,涵盖线程模型、Thread 与 Runnable、Lock 与 synchronized、原子类、并发容器、线程池(Executor 框架)、阻塞队列、并发工具类(CountDownLatch、Semaphore)、以及高并发系统设计中的关键策略。通过实战案例帮助学习者全面掌握构建高性能并发应用的工程能力。

60

2025.12.01

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

1

2026.01.13

PHP 高性能
PHP 高性能

本专题整合了PHP高性能相关教程大全,阅读专题下面的文章了解更多详细内容。

1

2026.01.13

MySQL数据库报错常见问题及解决方法大全
MySQL数据库报错常见问题及解决方法大全

本专题整合了MySQL数据库报错常见问题及解决方法,阅读专题下面的文章了解更多详细内容。

6

2026.01.13

PHP 文件上传
PHP 文件上传

本专题整合了PHP实现文件上传相关教程,阅读专题下面的文章了解更多详细内容。

4

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.5万人学习

C# 教程
C# 教程

共94课时 | 6.6万人学习

Java 教程
Java 教程

共578课时 | 45.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号