Snake - медленное время отклика на нажатие клавиши - PullRequest
0 голосов
/ 05 февраля 2019

Я сделал игру со змеями (пытаясь следовать коду ютубера), и направление контролируется WASD.Однако, когда я нажимаю одну из клавиш, ничего не происходит.Если я удерживаю его, он меняет направление, но происходит огромная задержка, вероятно, больше секунды.Как это исправить?Я просмотрел свой код и сравнил его с кодом YouTube, за которым следовал несколько раз, но все еще не могу понять, в чем проблема.Это первый раз, когда я создал игру, поэтому я очень новичок в этом.

Это видео, которому я пытался следовать, если это поможет.

https://www.youtube.com/watch?v=nK6l1uVlunc

package app;


import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.scene.shape.Rectangle;
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage; // Kontrollerer tittel, ikon, synlighet, størrelse, og dekorasjoner
import javafx.util.Duration;



public class App extends Application {

    public enum Direction {
        UP, DOWN, RIGHT, LEFT;
    }

    public static final int BLOCK_SIZE = 40;
    public static final int APP_W = 20 * BLOCK_SIZE;
    public static final int APP_H = 15 * BLOCK_SIZE;

    public int score = 0;
    public int highScore = 0;

    private Direction direction = Direction.RIGHT; // Default spawn-bevegelse: til høyre
    private boolean moved = false; 
    private boolean running = false; // Applikasjonen kjører

    private Timeline timeline = new Timeline();
    private ObservableList<Node> snake;

    private Parent createContent() {

        Pane root = new Pane();
        root.setPrefSize(APP_W, APP_H);

        Group snakeBody = new Group();
        snake = snakeBody.getChildren();    

        Rectangle food = new Rectangle(BLOCK_SIZE, BLOCK_SIZE);
        food.setFill(Color.RED);
        food.setTranslateX((int)(Math.random() * (APP_W - BLOCK_SIZE)) / BLOCK_SIZE * BLOCK_SIZE);
        food.setTranslateY((int)(Math.random() * (APP_H - BLOCK_SIZE)) / BLOCK_SIZE * BLOCK_SIZE);

        KeyFrame frame = new KeyFrame(Duration.seconds(0.5), event -> {
            if (!running)
                return;
            boolean toRemove = snake.size() > 1;

            Node tail = toRemove ? snake.remove(snake.size()-1) : snake.get(0);

            double tailX = tail.getTranslateX();
            double tailY = tail.getTranslateY();

            switch (direction) {
                case UP: 
                    tail.setTranslateX(snake.get(0).getTranslateX());
                    tail.setTranslateY(snake.get(0).getTranslateY() - BLOCK_SIZE);
                    break;
                case DOWN: 
                    tail.setTranslateX(snake.get(0).getTranslateX());
                    tail.setTranslateY(snake.get(0).getTranslateY() + BLOCK_SIZE);
                    break;
                case RIGHT: 
                    tail.setTranslateX(snake.get(0).getTranslateX() + BLOCK_SIZE);
                    tail.setTranslateY(snake.get(0).getTranslateY());
                    break;
                case LEFT: 
                    tail.setTranslateX(snake.get(0).getTranslateX() - BLOCK_SIZE);
                    tail.setTranslateY(snake.get(0).getTranslateY());
                    break;
            }

            moved = true;

            if (toRemove)
                snake.add(0, tail);

            // Kollisjonsdeteksjon

            // Krasjer i seg selv
            for (Node rect : snake) {
                if (rect != tail && tail.getTranslateX() == rect.getTranslateX() && tail.getTranslateY() == rect.getTranslateY()) {
                    restartGame();
                    break;
                }
            }

            // Krasjer i kant
            if (tail.getTranslateX() < 0 || tail.getTranslateX() >= APP_W || tail.getTranslateY() < 0 || tail.getTranslateY() >= APP_H) {
                restartGame();
            }

            // Legg til mat
            if (tail.getTranslateX() == food.getTranslateX() && tail.getTranslateY() == food.getTranslateY()) {
                food.setTranslateX((int)(Math.random() * (APP_W - BLOCK_SIZE)) / BLOCK_SIZE * BLOCK_SIZE);
                food.setTranslateY((int)(Math.random() * (APP_H - BLOCK_SIZE)) / BLOCK_SIZE * BLOCK_SIZE);

                Rectangle rect = new Rectangle(BLOCK_SIZE, BLOCK_SIZE);
                rect.setTranslateX(tailX);
                rect.setTranslateY(tailY);
                snake.add(rect);
            }



        });

        timeline.getKeyFrames().add(frame);
        timeline.setCycleCount(Timeline.INDEFINITE);

        root.getChildren().addAll(food, snakeBody);

        return root;
    }

    private void restartGame() {
        stopGame();
        startGame();
    }

    private void stopGame() {
        running = false;
        timeline.stop();
        snake.clear();
    }

    private void startGame() {
        direction = Direction.RIGHT;
        Rectangle head = new Rectangle(BLOCK_SIZE, BLOCK_SIZE);
        snake.add(head);
        timeline.play();
        running = true;
    }





    @Override
    public void start(final Stage primaryStage) throws Exception {
//      primaryStage.setTitle("My Application");
//      primaryStage.setScene(new Scene(FXMLLoader.load(App.class.getResource("App.fxml"))));
//      primaryStage.show();    

        Scene scene = new Scene(createContent());
        scene.setOnKeyPressed(event -> {
            if (!moved)

            switch (event.getCode()) {
                case W:
                    if (direction != Direction.DOWN)
                        direction = Direction.UP;
                    break;

                case S:
                    if (direction != Direction.UP)
                        direction = Direction.DOWN;
                    break;
                case A:
                    if (direction != Direction.RIGHT)
                        direction = Direction.LEFT;
                    break;
                case D:
                    if (direction != Direction.LEFT)
                        direction = Direction.RIGHT;
                    break;
            default:
                break;

            }
            moved = false;
        });

        primaryStage.setTitle("Snake");
        primaryStage.setScene(scene);
        primaryStage.show();
        startGame();
    }

    public static void main(final String[] args) {
        App.launch(args); // Kaller init(), start() og så stop()
    }

}

Ответы [ 2 ]

0 голосов
/ 05 февраля 2019

Проблема в том, что каждый раз, когда срабатывает KeyFrame, вы сбрасываете флаг moved.Это требует, чтобы пользователь инициировал как минимум 2 KEY_PRESSED события между кадрами, чтобы получить направление изменения.

Предполагая, что вы хотите запретить пользователю изменять направление перед первым кадром, вы должны удалить отрицание вif условие.(В зависимости от того, чего вы пытаетесь достичь с помощью флага, вам может потребоваться другое исправление).

scene.setOnKeyPressed(event -> {
    if (moved) {

        switch (event.getCode()) {
        case W:
            if (direction != Direction.DOWN)
                direction = Direction.UP;
            break;

        case S:
            if (direction != Direction.UP)
                direction = Direction.DOWN;
            break;
        case A:
            if (direction != Direction.RIGHT)
                direction = Direction.LEFT;
            break;
        case D:
            if (direction != Direction.LEFT)
                direction = Direction.RIGHT;
            break;
        default:
            break;

        }
    }
});

Также есть несколько вещей, которые можно улучшить в коде с помощью Map и добавление свойств к перечислению Direction.

public enum Direction {
    UP(0, -1), RIGHT(1, 0), DOWN(0, 1), LEFT(-1, 0);

    private final int dx;
    private final int dy;

    private Direction(int dx, int dy) {
        this.dx = dx;
        this.dy = dy;
    }

    /**
     * Tests, if 2 directions are parallel (i.e. both either on the x or the y axis).<br>
     * Note: Depends on the order of the enum constants
     * @param other the direction to compare with
     * @return true, if the directions are parallel, false otherwise
     */
    public boolean isParallel(Direction other) {
        return ((ordinal() - other.ordinal()) & 1) == 0;
    }
}

В KeyFrame

...
double tailX = tail.getTranslateX();
double tailY = tail.getTranslateY();

Node head = snake.get(0);
tail.setTranslateX(head.getTranslateX() + BLOCK_SIZE * direction.dx);
tail.setTranslateY(head.getTranslateY() + BLOCK_SIZE * direction.dy);

moved = true;
...
final Map<KeyCode, Direction> keyMapping = new EnumMap<>(KeyCode.class);
keyMapping.put(KeyCode.W, Direction.UP);
keyMapping.put(KeyCode.S, Direction.DOWN);
keyMapping.put(KeyCode.A, Direction.LEFT);
keyMapping.put(KeyCode.D, Direction.RIGHT);

Scene scene = new Scene(createContent());
scene.setOnKeyPressed(event -> {
    if (moved) {
        Direction newDirection = keyMapping.get(event.getCode());
        if (newDirection != null && !direction.isParallel(newDirection)) {
            direction = newDirection;
        }
    }

});
0 голосов
/ 05 февраля 2019

Я обнаружил разницу между вашим кодом и кодом из учебника.

if (!moved)
     return;

switch (event.getCode()) {
     .
     .
     .
}
moved = false;

В вашем коде отсутствует оператор возврата после if (! Moving).Я попытался добавить его в свой код, и после этого он работает для меня.

Надеюсь, это решит вашу проблему.Ура Малте

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...