这不是我第一次问这个问题,但是现在我对问题有了更好的了解。好的,所以我想做的是棋盘游戏。它有一堆瓷砖,每个转弯都可以从堆栈中占用一个瓷砖并将其添加到板上,然后是以下播放器的轮流等等。
。 使用鼠标添加瓷砖,并显示在边框内部的卷轴内部,该网格室(因为我们将在侧面,也许在顶部有更多东西(。
>让我们检查代码:
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((发生,所以我已经阅读了有关此的文档,但我没有得到清楚的答案。
顺便说一句,我指出我知道不会在正确的gridpane行中添加瓷砖,列,因为我不知道如何将像素转换为正确的gridpane位置,但这不是主要的问题。
我应该使用EventListener或EventFilter吗?它们有什么区别?如何使用它们?
首先,我建议阅读本教程以了解有关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
实例。这样,您可以使用视图和视图模型之间的数据绑定。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(
- Model-View-ViewModel(MVVM(
及其变化。这些体系结构通常(并非总是(使实现诸如GUI应用之类的软件变得更加容易。确定哪个最适合您的需求(如果有(并使用它。