Во-первых, я предлагаю прочитать этот учебник , чтобы узнать больше об обработке событий в 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. Если вы в конечном итоге используете фоновые потоки, не забывайте обновлять представление (прямо или косвенно) только в потоке приложений JavaFX .
Я также рекомендую прочитать статьи и учебные пособия о:
- Model-View-Controller (MVC)
- Model-View-Presenter (MVP)
- Модель-Вид-Вид-Модель (MVVM)
И их вариации. Эти архитектуры часто (не всегда) облегчают реализацию программного обеспечения, такого как приложения с графическим интерфейсом. Определите, какой из них лучше всего соответствует вашим потребностям (если есть), и используйте его.