WedX - журнал о программировании и компьютерных науках

JavaFX - перемещать снаряды

Во-первых, это мой самый первый пост здесь. Всем привет!

Я новичок в Java/JavaFX. В настоящее время я написал простую игру, чтобы изучить некоторые базовые вещи в разработке игр, и делаю это прямо сейчас просто для удовольствия. Пока что я получаю игрока, который двигается влево/вправо (движение не ограничено, но неважно, что сейчас) и стреляет снарядами. Я сделал это, код ниже:

package tester;

import java.util.ArrayList;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;


public class Tester extends Application {

    private int dx, x = 150, y = 470, projectileSpeed = 10;
    private int counter = 0, spawnTime = 180, enemySpeed = 4;
    private boolean goLeft, goRight, isShooting;

    public final static int APP_WIDTH = 300;
    public final static int APP_HEIGHT = 500;

    private AnchorPane root;
    private Scene scene;

    private Rectangle projectile;
    private Circle player = new Circle(x, y, 10, Color.RED);
    private Rectangle enemy;
    private ArrayList<Rectangle> projectiles = new ArrayList();
    private ArrayList<Rectangle> enemies = new ArrayList();

    @Override
    public void start(Stage primaryStage) {

        root = new AnchorPane();
        scene = new Scene(root, APP_WIDTH, APP_HEIGHT, Color.GHOSTWHITE);

        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.setResizable(false);
        primaryStage.show();

        root.getChildren().addAll(player);

        loop();
    }

    private void controls() {

        scene.setOnKeyPressed(event -> {
            KeyCode key = event.getCode();

            switch (key) {
                case LEFT:
                    goLeft = true;
                    break;
                case RIGHT:
                    goRight = true;
                    break;
                case SPACE:
                    projectiles.add(projectile = new Rectangle(3, 3, Color.BLUE));
                    projectile.relocate(x + player.getRadius(), y);
                    root.getChildren().add(projectile);
                    break;
            }

        });
        scene.setOnKeyReleased(event -> {
            KeyCode key = event.getCode();

            switch (key) {
                case LEFT:
                    goLeft = false;
                    break;
                case RIGHT:
                    goRight = false;
                    break;
                case SPACE:
                    isShooting = false;
                    break;
            }

        });

    }

    private void shoot() {
        for (int i = 0; i < projectiles.size(); ++i) {
            if (projectiles.get(i).getLayoutY() > (root.getBoundsInParent().getMinY() - projectile.getHeight())) {
                projectiles.get(i).relocate(projectiles.get(i).getLayoutX(), (projectiles.get(i).getLayoutY() - projectileSpeed));
            } else {
                projectiles.remove(i);
                root.getChildren().remove(i);
            }
        }

    }

    private void spawnEnemy() {

        double spawnPosition = Math.random();

        int eWidth = 20;
        int eHeight = 40;
        double ex = (APP_WIDTH - eWidth) * spawnPosition;
        int ey = (int) (root.getBoundsInParent().getMinY());

        if (counter % spawnTime == 0) {
            enemies.add(enemy = new Rectangle(ex, ey, eWidth, eHeight));
            root.getChildren().add(enemy);
        }
    }

    public void moveEnemy() {
        for (int i = 0; i < enemies.size(); ++i) {
            if (enemies.get(i).getLayoutY() < (root.getBoundsInParent().getMaxY() + enemy.getHeight())) {
                enemies.get(i).relocate(enemies.get(i).getLayoutX(), (enemies.get(i).getLayoutY() + enemySpeed));
            } else {
                enemies.remove(i);
                
            }
        }
    }

    private void loop() {

        AnimationTimer timer = new AnimationTimer() {

            @Override
            public void handle(long now) {

                controls();
                if (goLeft) {
                    dx = -5;
                }
                if (goRight) {
                    dx = 5;
                }
                if (!goLeft && !goRight) {
                    dx = 0;
                }
                player.relocate(x += dx, y);
                shoot();

                counter++;
                spawnEnemy();
                moveEnemy();
            }
        };
        timer.start();
    }

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

}

Теперь самое странное. Если я закомментирую метод moveEnemy(), все будет выглядеть нормально — враги (черные прямоугольники) появятся в случайных местах вдоль оси x в верхней части корня.

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

Большое спасибо!

Редактировать: может быть, я не ясно выразился. Я жду не готового решения, а объяснения.

17.04.2020

  • просто любопытно: почему вы регистрируете новый обработчик onKeyXX в каждом цикле? 18.04.2020
  • ваш ход кажется неправильным: вы не хотите переместить его в направлении x? также удаление в блоке else вызовет проблемы: вы делаете это во время цикла, тем самым уменьшая размер списка врагов. 18.04.2020
  • @kleopatra, ты прав, помещать обработчики в цикл было идиотизмом, даже не заметил этого, спасибо! Также удалены методы удаления из операторов else. Что касается направления движения, враги должны двигаться вниз (y+), к игроку. 18.04.2020
  • Хорошо, у меня работает код! Еще одна вещь: как указал @kleopatra, метод remove() в операторах else вызовет проблемы. Итак, теперь вопрос: как правильно избавиться от снарядов и врагов, которые выходят за пределы корневой панели? 21.04.2020
  • используйте итератор (и его удаление) или цикл с конца. 21.04.2020

Ответы:


1

Хорошо, я разобрался, спасибо Клеопатре за помощь! Вероятно, есть еще место для улучшения, но, тем не менее, есть определенный прогресс:

package tester;

import java.util.ArrayList;
import java.util.Iterator;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class Tester extends Application {

    private int dx, x = 150, y = 470, projectileSpeed = 10;
    private int counter = 0, spawnTime = 180, enemySpeed = 4;
    private boolean goLeft, goRight, isShooting;

    public final static int APP_WIDTH = 300;
    public final static int APP_HEIGHT = 500;

    private AnchorPane root;
    private Scene scene;

    private Rectangle projectile;
    private Circle player = new Circle(x, y, 10, Color.RED);
    private Rectangle enemy;

    private ArrayList<Rectangle> projectiles = new ArrayList();
    private ArrayList<Rectangle> enemies = new ArrayList();

    @Override
    public void start(Stage primaryStage) {

        root = new AnchorPane();
        scene = new Scene(root, APP_WIDTH, APP_HEIGHT, Color.GHOSTWHITE);

        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.setResizable(false);
        primaryStage.show();

        root.getChildren().addAll(player);

        controls();
        loop();
    }

    private void controls() {

        scene.setOnKeyPressed(event -> {
            KeyCode key = event.getCode();

            switch (key) {
                case LEFT:
                    goLeft = true;
                    break;
                case RIGHT:
                    goRight = true;
                    break;
                case SPACE:
                    if (!isShooting) {
                        projectiles.add(projectile = new Rectangle(2, 10, Color.ORANGERED));
                        projectile.relocate(x + player.getRadius(), y);
                        root.getChildren().add(projectile);
                        isShooting = true;
                        break;
                    }
            }

        });
        scene.setOnKeyReleased(event -> {
            KeyCode key = event.getCode();

            switch (key) {
                case LEFT:
                    goLeft = false;
                    break;
                case RIGHT:
                    goRight = false;
                    break;
                case SPACE:
                    isShooting = false;
                    break;
            }

        });

    }

    private void shoot() {
        for (int i = 0; i < projectiles.size(); ++i) {
            projectiles.get(i).relocate(projectiles.get(i).getLayoutX(), (projectiles.get(i).getLayoutY() - projectileSpeed));
        }

        Iterator<Rectangle> iterator = projectiles.iterator();

        while (iterator.hasNext()) {
            projectile = iterator.next();
            if (projectile.getLayoutY() < root.getLayoutY()) {

                iterator.remove();
                root.getChildren().remove(projectile);

            }
        }

    }

    private void spawnEnemy() {

        double spawnPosition = Math.random();

        int eWidth = 20;
        int eHeight = 40;
        double ex = (int) ((APP_WIDTH - eWidth) * spawnPosition);
        int ey = (int) (root.getLayoutY());

        if (counter % spawnTime == 0) {

            enemy = new Rectangle(eWidth, eHeight);
            enemy.relocate(ex, ey);
            enemies.add(enemy);
            root.getChildren().add(enemy);
        }

    }

    public void moveEnemy(int delta) {

        for (int i = 0; i < enemies.size(); ++i) {
            enemies.get(i).setY(enemies.get(i).getY() + delta);
        }

        Iterator<Rectangle> iterator = enemies.iterator();

        while (iterator.hasNext()) {
            enemy = iterator.next();
            if (enemy.getLayoutY() < root.getLayoutY()) {

                iterator.remove();
                root.getChildren().remove(enemy);

            }
        }
    }

    private void loop() {

        AnimationTimer timer = new AnimationTimer() {

            @Override
            public void handle(long now) {

                if (goLeft) {
                    dx = -5;
                }
                if (goRight) {
                    dx = 5;
                }
                if (!goLeft && !goRight) {
                    dx = 0;
                }
                player.relocate(x += dx, y);
                shoot();

                counter++;

                spawnEnemy();
                moveEnemy(4);

            }
        };
        timer.start();
    }

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

}

Теперь я немного поиграюсь с кодом, попробую обнаружить коллизии, ограничить движение, добавить еще кое-что и т. д.

21.04.2020
Новые материалы

Как проанализировать работу вашего классификатора?
Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

Работа с цепями Маркова, часть 4 (Машинное обучение)
Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

Учебные заметки: создание моего первого пакета Node.js
Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..

ИИ в аэрокосмической отрасли
Каждый полет – это шаг вперед к великой мечте. Чтобы это происходило в их собственном темпе, необходима команда астронавтов для погони за космосом и команда технического обслуживания..


Для любых предложений по сайту: [email protected]