В JavaFX как сохранить в центре окна движущийся символ, нарисованный на холсте?

#javafx #canvas

Вопрос:

Я очень новичок в JavaFX и в настоящее время работаю над игрой, подобной rouge, в 2D, которая использует графический интерфейс, созданный с помощью JavaFX. Движущийся персонаж нарисован на холсте с помощью GraphicContext2D. Есть только один холст, и я хотел бы решить свою проблему без наложения, если это возможно. Холст добавляется в область границ в качестве центра, Сцена, созданная с помощью этой области границ, для сцены, на которой была установлена эта сцена. Холст перерисовывается после перемещения с персонажем на KeyEvent. Я уже изменил размер сцены. Все работает хорошо, за исключением того, что я просто не могу удерживать своего движущегося персонажа в центре окна, а когда холст больше окна, он может выйти из этого окна. Как я могу удержать моего дорогого подвижного персонажа посередине?

Хорошо, вот очень, очень упрощенная версия, но с той же проблемой, персонаж не остается посередине, он может убежать из окна, а затем вернуться, когда холст установлен больше, чем окно.

 public class Main extends Application {

    String[][] map = new String[40][20];
    int[] playerCoords = {3,10};

    //colored.png downloaded from https://kenney.nl/assets/bit-pack
    Image tileset = new Image("/colored.png", 815 * 2, 373 * 2, true, false);
    Canvas canvas = new Canvas(
            20 * 32,
            40 * 32);
    GraphicsContext context = canvas.getGraphicsContext2D();

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

    @Override
    public void start(Stage stage){
        BorderPane borderPane = new BorderPane();
        borderPane.setCenter(canvas);
        map[3][10] = "p";

        refresh();
        Scene scene = new Scene(borderPane);
        scene.setOnKeyPressed(keyEvent -> {switch (keyEvent.getCode()) {
            case UP:
                this.movePlayer(true);
                refresh();
                break;
            case DOWN:
                this.movePlayer(false);
                refresh();
                break;}});
        stage.setScene(scene);
        stage.show();
    }

    void movePlayer(boolean up){
        int direction = up ? -1 : 1;
        int newPosRow = playerCoords[0]   direction;
        if ( newPosRow >= 0 amp;amp; newPosRow < map.length) {
            map[playerCoords[0]][playerCoords[1]] = null;
            playerCoords[0] = newPosRow;
            map[playerCoords[0]][playerCoords[1]] = "p";
        }
    }

    void refresh(){
        context.setFill(Color.BLACK);
        context.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
        for (int i = 0; i < map.length; i   ){
            for (int j = 0; j < map[0].length; j  ){
                if (map[i][j] != null amp;amp; map[i][j].equals("p")){
                    //player Tile 28, 0
                    context.drawImage(tileset, 952,0, 32,32,j * 32,i * 32, 32,32);
                } else{
                    context.drawImage(tileset, 0,0, 32,32,j * 32,i * 32, 32,32);
                }
            }
        }
    }

}
 

Комментарии:

1. Этот метод context.drawImage немного сложен, это случилось и со мной, когда многие номера входных параметров были неверными. Также я использую отдельное приложение класса для запуска приложения, но оно действительно короткое, оно просто вызывает Main.main(args).

2. Его можно загрузить с kenney.nl/assets/bit-pack

3. Я заметил, что я не использую точно такой же png, но я проверил его с помощью этого текущего, который я загрузил несколько минут назад, он работает с ним, просто не очень хорошо, потому что для этого эти цифры в context.drawImage должны быть скорректированы.

4. Хорошо, не в contect.drawImage, а вверху, где я прочитал png для создания объекта изображения, набор листов. Размер файла составляет 815 x 373.

5. Исправлен размер файла в приведенном здесь примере кода.

Ответ №1:

Хорошо, так что, похоже, в настоящее время не существует простого решения JavaFX. Но если кто-то знает одного, спасибо, что поделился. 🙂 Тем временем я подумал об алгоритмическом решении путем преобразования координат в соответствии с абсолютными и относительными (игрок, помещенный посередине) координатами игрока. Он очень далек от совершенства, он изменяет только строки карты, так как в этом примере игрок может перемещаться только по вертикали, и он работает с холстом, не намного превышающим размер окна. Мне нужно было изменить только метод обновления. Есть кое-что, чего я на данный момент не понимаю, это работает с вычитанием centerCol из строки игрока.

 int centerRow = map.length/2;
int centerCol = map[0].length/2;
int mapRowDiff = playerCoords[0] - centerCol;
 

не с вычитанием центральной строки из строки игрока

 int centerRow = map.length/2;
int centerCol = map[0].length/2;
int mapRowDiff = playerCoords[0] -  centerRow; 
 

Но, по крайней мере, это начало работать.
И вот мое обновление() с преобразованием, оно стало немного сложным.

     void refresh(){
        context.setFill(Color.BLACK);
        context.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
        int centerRow = map.length/2;
        int centerCol = map[0].length/2;
        int mapRowDiff = playerCoords[0] - centerCol;
        for (int i = 0; i < map.length; i   ){
            for (int j = 0; j < map[0].length; j  ){
                if (mapRowDiff >= 0
                        amp;amp; mapRowDiff < map.length) {
                    if (map[mapRowDiff][j] != null amp;amp; map[mapRowDiff][j].equals("p")) {
                        //player Tile 28, 0
                        context.drawImage(tileset, 952, 0, 32, 32, j * 32, i * 32, 32, 32);
                    } else {
                        context.drawImage(tileset, 0, 0, 32, 32, j * 32, i * 32, 32, 32);
                    }
                } else {
                    context.drawImage(tileset, 0, 34, 32, 32, j * 32, i * 32, 32, 32);
                }
            }
            mapRowDiff  ;
        }
    }