仿制Jetpack Joyride游戏时空格控制的物理逻辑不生效问题求助
问题排查与修复方案
核心问题点
- 你写的
spaceHeld状态判断逻辑仅在Game类构造函数执行时运行了一次,后续按下/松开空格键修改spaceHeld值时,不会重新触发计时器启停/切换逻辑,所以游戏启动后只会跑初始启动的重力计时器,永远不会切飞行逻辑。 - 你使用了
java.util.Timer,它的回调是在后台线程执行的,直接修改Swing组件(JLabel的位置)属于跨线程操作Swing组件,会出现不可预知的渲染问题,甚至崩溃,应该使用javax.swing.Timer,它的回调默认在Swing事件调度线程执行,符合Swing单线程模型要求。 - 初始角色坐标设置错误:你给player设置的初始y坐标是1800,但窗口高度只有1080,游戏启动后角色直接在窗口可视区域外,就算逻辑正常你也看不到角色移动。
- 两个独立计时器逻辑冲突:如果后续你触发了两个计时器同时运行,重力和上升逻辑同时执行,会出现速度计算混乱的问题。
修复方案
建议把重力和飞行的逻辑合并到同一个Swing Timer的回调中,每次回调根据当前spaceHeld的值执行对应逻辑,不用维护两个Timer,逻辑更简单也不会冲突。
修复后完整代码
import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Game implements KeyListener { JFrame frame; JLabel player; public boolean grounded = false; public int velocity = 0; public boolean spaceHeld = false; Game() { frame = new JFrame("Nicholas Seow-Xi Crouse"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(1920, 1080); frame.setLayout(null); frame.setFocusable(true); frame.addKeyListener(this); player = new JLabel(); player.setBackground(Color.red); // 修正初始y坐标,让角色一开始在窗口底部可见 player.setBounds(10, 990, 50, 50); player.setOpaque(true); frame.add(player); frame.setVisible(true); // 合并逻辑的Swing Timer,33ms执行一次,约30帧 Timer gameTimer = new Timer(33, e -> { if (spaceHeld) { // 飞行逻辑:上升 if(velocity > -5) { velocity -= 1; } else { velocity = -5; } } else { // 重力逻辑:下落 if(velocity < 5){ velocity += 1; } else { velocity = 5; } } // 计算新位置 int newY = player.getY() + velocity; // 边界判断:顶部不能超出窗口 if (newY <= 0) { newY = 0; velocity = 0; } // 边界判断:底部不能超出窗口(窗口高度1080,减去角色高度50) if (newY >= 1030) { newY = 1030; velocity = 0; } player.setLocation(player.getX(), newY); }); // 启动游戏主计时器 gameTimer.start(); } public void keyTyped(KeyEvent e) {} public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_SPACE){ spaceHeld = true; } } public void keyReleased(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_SPACE){ spaceHeld = false; } } public static void main(String[] args) { // Swing组件初始化要在EDT线程执行 SwingUtilities.invokeLater(Game::new); } }
额外优化说明
- 去掉了冗余的
finalY变量,直接用velocity计算每帧位移,逻辑更清晰 - 统一做边界判断,不用在两个逻辑里重复写
- 增加了main方法作为程序入口,添加了Swing初始化的线程合规处理
- 调整了边界值计算,避免角色超出窗口范围
内容的提问来源于stack exchange,提问作者ZZBowzer
相关产品推荐
相关产品推荐

