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

如何调整JavaFX AnimationTimer中键盘控制移动物体的速度且保持平滑

问题核心原因

你当前的实现将移动逻辑绑定在了键盘事件的触发时机上,而系统键盘的按键重复触发频率远低于JavaFX AnimationTimer的每秒60帧刷新率:步长设小了,受限于按键触发频率总移动速度慢;步长设大了,每次按键触发的跳跃幅度过大,自然就会出现卡顿跳变的效果。

实现思路
  • 新增布尔变量记录四个方向的按键按下状态,键盘事件仅负责更新状态,不直接修改坐标
  • 将坐标更新逻辑迁移到AnimationTimer的每帧回调中,根据当前按下的方向状态,每帧匀速更新坐标
  • 单独定义速度变量,调整速度时直接修改该变量即可,不会影响每帧更新的平滑度
修改后完整可运行代码
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.animation.AnimationTimer;

public class MainFX extends Application {

    private double playerX;
    private double playerY;
    // 按键状态标记
    private boolean upPressed = false;
    private boolean downPressed = false;
    private boolean leftPressed = false;
    private boolean rightPressed = false;
    // 移动速度,可按需调整,数值越大速度越快
    private static final double SPEED = 10.0;

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        AnchorPane pane = new AnchorPane();
        Scene scene = new Scene(pane, 800, 600);
        primaryStage.setScene(scene);
        primaryStage.show();

        playerX = pane.getWidth()/2;
        playerY = pane.getHeight()/2;
        Circle player = new Circle(playerX,playerY,10);
        pane.getChildren().add(player);

        // 处理按键按下事件
        scene.addEventHandler(KeyEvent.KEY_PRESSED, event -> {
            if (event.getCode() == KeyCode.UP) upPressed = true;
            if (event.getCode() == KeyCode.DOWN) downPressed = true;
            if (event.getCode() == KeyCode.LEFT) leftPressed = true;
            if (event.getCode() == KeyCode.RIGHT) rightPressed = true;
        });

        // 新增按键松开事件处理
        scene.addEventHandler(KeyEvent.KEY_RELEASED, event -> {
            if (event.getCode() == KeyCode.UP) upPressed = false;
            if (event.getCode() == KeyCode.DOWN) downPressed = false;
            if (event.getCode() == KeyCode.LEFT) leftPressed = false;
            if (event.getCode() == KeyCode.RIGHT) rightPressed = false;
        });

        AnimationTimer timer = new AnimationTimer() {
            @Override
            public void handle(long now) {
                // 每帧根据按键状态更新坐标
                if (upPressed) playerY -= SPEED / 60;
                if (downPressed) playerY += SPEED / 60;
                if (leftPressed) playerX -= SPEED / 60;
                if (rightPressed) playerX += SPEED / 60;
                // 更新组件位置
                player.setCenterX(playerX);
                player.setCenterY(playerY);
            }
        };
        timer.start();
    }
}
效果说明

调整SPEED变量的数值即可任意修改移动速度,因为坐标更新是每帧执行一次,哪怕SPEED设为100,也只会表现为移动速度极快,不会出现跳变卡顿的问题。同时支持多方向同时按下,实现斜向移动,操作体验也优于原有实现。

内容的提问来源于stack exchange,提问作者Filippo Fracascia

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 17:24:00