You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

仿制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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 01:09:00