如何在计时器运行时禁用键盘输入?解决角色移动按键冲突问题
解决方案
核心思路
用一个布尔变量标记角色是否处于移动状态,移动过程中直接忽略所有键盘输入;同时过滤非方向键的按键事件,避免无关操作触发故障。
具体实现步骤
- 添加全局布尔标志位,控制输入锁定:
private boolean isMoving = false; // 标记是否正在移动
- 修改
moveCharacter方法,先检查移动状态,再处理方向键,直接忽略其他按键:
@FXML public void moveCharacter(KeyEvent event) { // 正在移动时直接返回,忽略所有输入 if (isMoving) { return; } KeyCode code = event.getCode(); // 只处理方向键,其他按键直接忽略 if (!code.equals(KeyCode.D) && !code.equals(KeyCode.RIGHT) && !code.equals(KeyCode.A) && !code.equals(KeyCode.LEFT)) { return; } switch (code) { case D, RIGHT: try { moveForward(); } catch (URISyntaxException | InterruptedException e) { throw new RuntimeException(e); } break; case A, LEFT: try { moveBack(); } catch (URISyntaxException e) { throw new RuntimeException(e); } break; } }
- 修改
moveForward和moveBack方法,在Timer调度移动的前后更新isMoving状态,确保移动完成后解锁输入:
private void moveForward() throws URISyntaxException { isMoving = true; // 开始移动,锁定输入 Timer timer = new Timer(); TimerTask task = new TimerTask() { int steps = 0; final int totalSteps = 10; // 假设移动需要10步完成 @Override public void run() { if (steps < totalSteps) { // 执行每一步的移动逻辑,比如修改角色坐标 character.setX(character.getX() + 5); steps++; } else { timer.cancel(); isMoving = false; // 移动完成,解锁输入 } } }; timer.scheduleAtFixedRate(task, 0, 50); // 每50ms执行一步 } // moveBack方法同理,只需修改移动方向 private void moveBack() throws URISyntaxException { isMoving = true; Timer timer = new Timer(); TimerTask task = new TimerTask() { int steps = 0; final int totalSteps = 10; @Override public void run() { if (steps < totalSteps) { character.setX(character.getX() - 5); steps++; } else { timer.cancel(); isMoving = false; } } }; timer.scheduleAtFixedRate(task, 0, 50); }
为什么之前的方案无效?
- 时间阈值方案:Timer的异步执行和按键事件的触发是独立的,可能在Timer还没完成时,时间阈值已经满足,导致新的输入被处理,冲突引发故障。
- Thread.sleep:JavaFX的UI操作必须在主线程执行,sleep会阻塞主线程,导致所有UI更新被延迟到sleep结束后一次性执行,看起来像瞬移。
内容的提问来源于stack exchange,提问作者Zhe Hin Yap
相关产品推荐
相关产品推荐

