在 JavaFX 中访问 GraphicsContext 中的元素 canvas

Accessing elements inside a GraphicsContext in JavaFX canvas

我正在按照 MVC 模式实现一个简单的曲棍球游戏。我无法刷新玩家的位置,这是我使用 GraphicsContext.drawImage() 方法在 canvas 中创建的。我在 AnimationTimer 匿名 class 中,在 handle 方法中。

位置和边界都反映到后端,所以我真的不需要在这里做任何特定的逻辑,我只是​​想根据模型内部计算的位置在每一帧刷新玩家的位置,但我无法以任何方式访问我之前绘制的图像。这是代码:

DefaultController controller;

@FXML
public void initialize() {
    
    controller = new DefaultController(800, 400);
    
    double playerX = controller.getField().getPlayer().getX();
    double playerY = controller.getField().getPlayer().getY();
    
    double enemyX = controller.getField().getEnemy().getX();
    double enemyY = controller.getField().getEnemy().getY();

    context.drawImage(new Image("player.png"),playerX, playerY);
    context.drawImage(new Image("enemy.png"),enemyX, enemyY);

    AnimationTimer timer = new AnimationTimer() {
        @Override
        public void handle(long now) {
            pane.getScene().addEventHandler(KeyEvent.KEY_PRESSED, (key) -> {
                if (key.getCode() == KeyCode.UP) {
                    controller.getField().getPlayer().setLocation(playerX,playerY-0.1)

                    // how do I update the player image position inside the canvas?
                }
            });
        }
    };
    timer.start();
}

您采用了完全错误的方法。 Canvas 中的任何内容一旦绘制完成就无法更新。您可以将其擦除并重新绘制。对于您正在尝试做的事情,场景图更适合。

以下是 mre 演示如何使用向上键在 canvas 上移动图像:

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.*;
import javafx.scene.image.Image;
import javafx.scene.input.*;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class Main extends Application {

    private static final int SIZE = 200;
    private static final String FISH_IMAGE = "https://www.shareicon.net/data/128x128/2015/03/28/14104_animal_256x256.png";
    private Image image;
    private Canvas canvas;
    private final double xPos = 250;
    private double yPos = 150;
    private static final double MOVE = 0.8;
    @Override
    public void start(Stage primaryStage) {

        image = new Image(FISH_IMAGE,SIZE,SIZE,false,false);
        canvas = new Canvas(SIZE*3, SIZE*3);
        draw();
        Scene scene = new Scene(new StackPane(canvas));
        scene.addEventHandler(KeyEvent.KEY_PRESSED, (key) -> animate(key));
        primaryStage.setScene(scene);
        primaryStage.show();

        AnimationTimer timer = new AnimationTimer() {
            @Override
            public void handle(long now) {
                //to avoid multiple handlers do not add handler here
                draw();
            }
        };
        timer.start();
    }
    
    private void animate(KeyEvent key){
          if(key.getCode()== KeyCode.UP) {
            yPos -= MOVE;
          }
          //todo add down, left , right 
         //for low rate animation, like response to key-press, invoke draw() here instead of using AnimationTimer 
    }

    private void draw(){
         GraphicsContext gc = canvas.getGraphicsContext2D();
         gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());//clear previous
         gc.drawImage(image, xPos, yPos);
    }

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