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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 11:57:03