JavaFX Canvas中GraphicsContext绘制的元素如何在动画帧中更新位置
JavaFX Canvas 冰球游戏位置刷新解决方案
Canvas 是立即模式渲染组件,调用GraphicsContext.drawImage()绘制的内容会直接以像素形式固化到画布上,不存在可直接操作的独立图像对象,你没法直接修改之前绘制元素的位置,正确的实现逻辑是逐帧清空画布,再根据Model层的最新位置数据重新绘制所有画面元素。
你现有代码还有两处逻辑错误需要修正:
- 不要把键盘事件注册放在
AnimationTimer的handle方法中:handle方法每秒会触发约60次,你相当于每秒新增60个相同的键盘监听器,会导致严重卡顿和逻辑重复执行 - 初始化时定义的
playerX/playerY是固定的常量,不会跟随Model层数据自动更新,每次绘制需要实时从Model中读取最新坐标
修改后的参考代码如下:
DefaultController controller; // 提前加载图片资源,不要每次绘制都重复创建 Image playerImg = new Image("player.png"); Image enemyImg = new Image("enemy.png"); // 画布尺寸和你初始化Controller的参数对应 final int CANVAS_WIDTH = 800; final int CANVAS_HEIGHT = 400; @FXML public void initialize() { controller = new DefaultController(CANVAS_WIDTH, CANVAS_HEIGHT); // 键盘监听只注册一次,放在AnimationTimer外面 pane.getScene().addEventHandler(KeyEvent.KEY_PRESSED, (key) -> { if (key.getCode() == KeyCode.UP) { // 直接修改Model层的位置即可,不需要在这里操作视图 double currentY = controller.getField().getPlayer().getY(); double currentX = controller.getField().getPlayer().getX(); controller.getField().getPlayer().setLocation(currentX, currentY - 0.1); } }); AnimationTimer timer = new AnimationTimer() { @Override public void handle(long now) { // 1. 清空整个画布 context.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT); // 2. 从Model层取最新坐标 double playerX = controller.getField().getPlayer().getX(); double playerY = controller.getField().getPlayer().getY(); double enemyX = controller.getField().getEnemy().getX(); double enemyY = controller.getField().getEnemy().getY(); // 3. 重绘所有元素 context.drawImage(playerImg, playerX, playerY); context.drawImage(enemyImg, enemyX, enemyY); } }; timer.start(); }
内容的提问来源于stack exchange,提问作者Filippo Fracascia
相关产品推荐
相关产品推荐

