Java Swing开发类Jetpack Joyride游戏的空格键按住绑定实现问题
Java Swing Jetpack类游戏空格按住检测修复方案
核心问题梳理
- 仅绑定了空格键按下触发事件,未绑定松开事件,无法将
spaceHeld重置为false - 重力、上升逻辑的计时器仅在构造函数中执行一次调度判断,后续
spaceHeld状态变化时不会切换运行逻辑 - 用
java.util.Timer属于后台线程,直接操作Swing组件存在线程安全风险,两个计时器并行运行还会导致速度计算逻辑冲突 - 玩家初始Y坐标设为1800,超出了窗口1080的高度,初始状态完全不可见
修复代码
import java.awt.Color; import java.awt.event.*; import javax.swing.*; public class Game { JFrame frame; JLabel player; boolean grounded = true; // 初始状态在地面 int velocity = 0; boolean spaceHeld = false; Action spacePressAction; Action spaceReleaseAction; Timer gameLoopTimer; Game() { frame = new JFrame("Nicholas Seow-Xi Crouse"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(1920, 1080); frame.setLayout(null); frame.setResizable(false); player = new JLabel(); player.setBackground(Color.red); // 修正初始位置,Y轴990刚好贴合窗口底部 player.setBounds(10, 990, 50, 50); player.setOpaque(true); // 绑定空格按下事件 全局窗口生效无需选中玩家组件 spacePressAction = new SpacePressAction(); player.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("SPACE"), "spacePress"); player.getActionMap().put("spacePress", spacePressAction); // 绑定空格松开事件 spaceReleaseAction = new SpaceReleaseAction(); player.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released SPACE"), "spaceRelease"); player.getActionMap().put("spaceRelease", spaceReleaseAction); frame.add(player); frame.setVisible(true); // 单游戏主循环 33ms刷新一次≈30帧 gameLoopTimer = new Timer(33, e -> { int playerY = player.getY(); // 边界判断:触底触发落地逻辑 if (playerY >= 990) { grounded = true; velocity = 0; player.setLocation(player.getX(), 990); return; } // 边界判断:触顶限制位置 if (playerY <= 0) { velocity = 0; player.setLocation(player.getX(), 0); } grounded = false; // 根据空格状态更新速度 if (spaceHeld) { // 上升逻辑:限制最大上升速度为-5 velocity = Math.max(velocity - 1, -5); } else { // 重力下落逻辑:限制最大下落速度为5 velocity = Math.min(velocity + 1, 5); } // 更新玩家位置 player.setLocation(player.getX(), playerY + velocity); }); gameLoopTimer.start(); } // 空格按下触发 public class SpacePressAction extends AbstractAction { @Override public void actionPerformed(ActionEvent e) { spaceHeld = true; } } // 空格松开触发 public class SpaceReleaseAction extends AbstractAction { @Override public void actionPerformed(ActionEvent e) { spaceHeld = false; } } public static void main(String[] args) { // Swing组件初始化必须在事件调度线程执行 SwingUtilities.invokeLater(Game::new); } }
优化说明
- 输入绑定使用
WHEN_IN_FOCUSED_WINDOW,无需点击玩家组件也能全局响应键盘事件 - 替换为Swing自带的
Timer,所有逻辑运行在Swing事件线程,避免UI更新异常 - 合并上升、重力逻辑到同一个主循环,消除多计时器调度冲突问题
- 补充标准main入口,直接运行即可启动游戏,实现按住空格上升、松开空格下落的核心逻辑
内容的提问来源于stack exchange,提问作者ZZBowzer
相关产品推荐
相关产品推荐

