如何调整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
相关产品推荐
相关产品推荐

