События в Java (слушатель)

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

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

Давайте проверим код:

public final class GUI extends Application {

    private Game _game;
    private GridPane _visualBoard;
    private Stage _primaryStage;

    @Override
    public void start(final Stage primaryStage) {
    //stuff
    play();
    primaryStage.show();
}


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

public void addTile(myTile r) {
      double x, y;
      myVisualTile vT = new myVisualTile(r)
      _visualBoard.setOnMousePressed(new EventHandler<MouseEvent>() {
           @Override
           public void handle(MouseEvent e) {
               double mouseX = e.getSceneX();
               double mouseY = e.getSceneY();
              _visualBoard.add(vT, x, y);
           }
      });
}

public void play() {
    Player j;
    int i = 0;
    while (!_tileStack.empty()) {
        if (i == _players.size()) i = 0;
        j = _players.get(i);
        i++;
        turn(j);
    }
    System.out.println("Final");
}

private void turn(Player j) {
    myTile r=_tileStack.poll();
    addTile(r);
}

Но на самом деле это не работает так, как должно. Почему? Потому что КАК-ТО я должен «слушать», чтобы произошло событие addTile(), поэтому я прочитал документацию об этом, но не получил четкого ответа.

Кстати, позвольте мне отметить, что я знаю, что плитки не будут добавлены в правильную строку сетки, столбец, поскольку я не знаю, как преобразовать пиксели в правильную позицию сетки, но это не главный вопрос.

Должен ли я использовать EventListener или EventFilter? В чем разница между ними? Как их использовать?

Пожалуйста, опубликуйте минимальный воспроизводимый пример

c0der 20.05.2019 06:09
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
1
119
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Во-первых, я предлагаю прочитать этот учебник, чтобы узнать больше об обработке событий в JavaFX.


Судя по этому вопросу и двум другим, концептуальная проблема, с которой вы столкнулись, заключается в том, как получить «петлю без петли».

Идея в том, что у вас должен быть класс, представляющий состояние игры. «Состояние» включает в себя такие вещи, как чей сейчас ход, какие плитки были размещены, какие плитки все еще доступны, какие ходы действительны, сколько очков у каждого человека, была ли игра выиграна и так далее.

public class Game {

    private final Deque<Tile> tileStack = ...;
    private final Tile[][] board = ...; // where "null" would be open (might want a better data structure)
    private final List<Player> players = ...;
    private final Map<Player, Integer> points = ...;
    private int currentPlayerIndex;

    private Tile currentTile;

    // getters/setters (if necessary)...
}

Я полагаю, что при использовании шаблона проектирования, такого как MVVM, выше будет ViewModel. И поскольку вы используете JavaFX, вы можете захотеть представить эти свойства как фактические экземпляры JavaFX [ReadOnly]Property. Таким образом, вы можете использовать привязку данных между View и ViewModel. Такие вещи, как Player и Tile, будут объектами модели.

Затем вы добавите в этот класс методы для управления состоянием игры.

public void tryPlaceTile(int row, int column) {
    if (isValidMove(row, column) {
        addPlacedTile(row, column); // might update points
        if (tileStack.isEmpty()) {
            currentTile = null;
            endGame(); // stops the game, determines winner
        } else {
            currentTile = tileStack.pop();
            currentPlayerIndex = currentPlayerIndex == players.size() - 1 ? 0 : currentPlayerIndex + 1;
            updateView(); // likely not needed with data binding
        }
    } else {
        notifyUserOfInvalidMove();
    }

    // let method simply return, it will be called again when
    // the (next) player clicks in the appropriate place of
    // the view
}

Теперь два приведенных выше фрагмента кода чрезвычайно грубы (особенно потому, что я не очень хорошо знаком с игрой, которую вы кодируете). Такие вещи, как updateView(), не обязательно нужны при использовании привязки данных. isValidMove(int,int) и notifyUserOfInvalidMove() также не обязательно нужны, если представление (на основе состояния игры) не позволяет взаимодействовать с недопустимыми локациями. Но дело в том, что когда пользователь нажимает на местоположение, вы вызываете этот метод. Этот метод обрабатывает ход игрока и обновляет состояние игры. Изменение состояния должно влиять на представление, чтобы визуальные элементы точно отображали состояние1. Как только метод вернется, вы вернетесь к «ожиданию» следующего взаимодействия с пользователем.

node.setOnMouseClicked(event -> {
    gameInstance.tryPlaceTile(/* needed information */);
    // anything else that needs doing
});

1. If you end up using background threads, remember to only ever update the view (directly or indirectly) on the JavaFX Application Thread.


Я также рекомендую прочитать статьи и учебные пособия о:

  • Модель-представление-контроллер (MVC)
  • Модель-представление-презентатор (MVP)
  • Модель-представление-ViewModel (MVVM)

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

Извините, но я не вижу никакой разницы между моим кодом и вашими примерами. Я имею в виду; в addTile() у меня есть node.setOnMouseClicked(event -> {, а затем в методе обработки у меня есть обновление игры. Но основной цикл не ждет выполнения действия.

Joel Perez 20.05.2019 04:46

Не иметь петли. Вызываемый обработчик событий будет эквивалентен итерации цикла один.

Slaw 20.05.2019 04:50

Затем мне нужен способ узнать, когда игра заканчивается, и в теории это зависит от оставшихся плиток (когда tileStack пуст, игра окончена. Кроме того, мне нужен способ передать ход, и обе вещи выполняются в петля.

Joel Perez 20.05.2019 04:53

Да! Попробую так.

Joel Perez 20.05.2019 11:45

Вот и все! Проблема была в том, что я усвоил урок, а не в приложении javaFX. Теперь нужно знать, как преобразовать щелчок мыши в положение сетки.

Joel Perez 20.05.2019 12:14

Другие вопросы по теме