我的代码的MCVE版本已经用于帮助调试它。它重现了我的错误。我的代码的目的是做一个记忆游戏。这意味着当轮到你时,你打开"一张卡片,然后是另一张卡片。如果他们形成一对,他们就不会被翻身,他们会保持开放。否则,你将它们翻过来并尝试在下一回合找到一对。
简单地说,错误是:当你打开转牌的第二张牌并且两张牌都没有形成一对时,第二张牌永远不会被打开!
希望这个版本的代码可以帮助您找到错误,这对我有很大的帮助!
我已将代码放在Github上:https://gist.github.com/anonymous/e866671d80384ae53b53 (你会在问题的最后找到附加)
我很高兴在JavaFX中做一个小内存游戏,我遇到了这种奇怪的行为,我点击的卡片(由扩展Button类的自定义类表示)从不改变显示的图像。
通常情况下,当我点击卡片时,它会打开"本身通过更改它显示的图形。 奇怪而恼人的是它只发生在特定的情况下。
当我打开&#34>我的卡的行为是正确的。玩家回合的第一张牌。它也适用于我打开"第二个,两张卡都是一对。可悲的是,它只适用于我想打开第二张卡并且与第一张卡不匹配的情况。
我通过添加openCard()
和closeCard()
方法修改了Button类。这些方法将在按钮卡上设置一个特定的图形。
我现在将展示一些代码,但很难说出可能导致此行为发生的部分。更重要的是,我正在使用Eclipse,但无法弄清楚如何使用断点调试JavaFX应用程序(我正在使用控制台打印),因为当我到达断点并开始爬行时,应用程序最终会崩溃代码。
首先,修改后的Button类:
public class Card extends Button{
private String cardDesign;
public Card(int row, int column){
this.setGraphic(new ImageView("/resources/card_back.png"));
this.setBackground(new Background(new BackgroundFill(Color.SLATEGRAY,
new CornerRadii(6), null)));
}
public void setOpenCardDesign(String design){ cardDesign = design; }
public void openCard(){ this.setGraphic(new ImageView(cardDesign)); }
public void closeCard(){
this.setGraphic(new ImageView("/resources/card_back.png"));
}
}
现在是控制器类,事件在MouseEvent
上设置。这个控制器中有更多的代码(比如检查是否有一对),但这不是一个问题,我认为问题已经出现在我称之为打开卡的方法的行上。
我在这里使用getSource()
方法因为我的卡被安排在gridPane中,我需要知道哪一个被点击了。
@Override
public void handle(MouseEvent event) {
//Get the card that was clicked on
Card card = (Card) event.getSource();
//Open the card
card.openCard();
//Do some more after this...
}
根据我的想法,这几乎就是这样。
如前所述,我试图检查是否正在调用方法openCard()
。就像在我的控制台中打印出的一些评论一样。我甚至在我设置图形的行之前和之后添加了一些控制台打印,它们都出现了。我无法确切知道当我的应用到达setGraphic()
行时会发生什么,因为我的应用中没有任何内容显示(卡片仍处于关闭状态)。
任何提示都会有所帮助,因为我现在正在疯狂地沉沦。 提前谢谢。
卡片对象:Card.java
package memory;
import javafx.scene.control.Button;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.paint.Color;
public class Card extends Button{
//-------------------------------------------------
//Store the position of the card
private int row;
private int column;
//-------------------------------------------------
//Constructor
public Card(int row, int column){
//Give the cards a specific color at init
this.setBackground(new Background(new BackgroundFill(Color.DEEPSKYBLUE,
new CornerRadii(6), null)));
this.setText("CLOSED");
this.row = row;
this.column = column;
}
//-------------------------------------------------
//Open the card
public void openCard(){
System.out.println("OPEN");
//Cards are red when open
this.setBackground(new Background(new BackgroundFill(Color.RED,
new CornerRadii(6), null)));
this.setText("OPEN");
}
//-------------------------------------------------
//Close the card
public void closeCard(){
System.out.println("CLOSE");
//Cards are blue when closed
this.setBackground(new Background(new BackgroundFill(Color.DEEPSKYBLUE,
new CornerRadii(6), null)));
this.setText("CLOSED");
}
//-------------------------------------------------
//Getters for row and column info
public int getRow() { return row; }
public int getColumn() { return column; }
}
主要(包括应用的观点和起点):Main.java
package memory;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class Main extends Application {
//-------------------------------------------------
//The layout and the cards
GridPane gridCard = new GridPane();
static Card [][] cardArray;
//The event handler
private static EventHandler<MouseEvent> handler;
//The array which remembers the pairs and the reminder of last open card
static int[][] indexArray;
static int index;
//Boolean array to check if the card is already open
static boolean[][] isOpen;
//Number of pairs to find
static int pairs = 5;
//-------------------------------------------------
//Cheap main
public static void main(String[] args) {
Application.launch(args);
}
//-------------------------------------------------
@Override
public void start(Stage primaryStage) throws Exception {
//Init the event handler
handler = new Controller();
//Some formatting for the grid pane
gridCard.setHgap(10);
gridCard.setVgap(10);
gridCard.setPadding(new Insets(0, 10, 0, 10));
gridCard.setAlignment(Pos.CENTER);
//Creating our card board, index array and bool array
cardArray = new Card [2][5];
indexArray = new int [2][5];
isOpen = new boolean [2][5];
//Adding the cards to our card array
for(int i = 0; i < 2; i++){
for(int j = 0; j < 5; j++){
cardArray[i][j] = new Card(i, j);
//Make those buttons look like cards
cardArray[i][j].setPrefHeight(100);
cardArray[i][j].setPrefWidth(70);
//Register the event
cardArray[i][j].addEventHandler(MouseEvent.MOUSE_CLICKED, gameController());
//Add those cards
gridCard.add(cardArray[i][j], j, i);
//Set the pairs (no randomness here)
indexArray[i][j] = j+1;
}
}
//Print out the indexes of all the cards
System.out.println("----------------");
System.out.println("Card indexes :");
for (int i = 0; i < indexArray.length; i++) {
System.out.println();
for (int j = 0; j < indexArray[0].length; j++) {
System.out.print(indexArray[i][j]+ " | ");
}
System.out.println();
}
System.out.println("----------------");
//Set BorderPane
BorderPane root = new BorderPane();
root.setBackground(new Background(new BackgroundFill(Color.BLACK,
CornerRadii.EMPTY, null)));
root.setCenter(gridCard);
//Set the stage
primaryStage.setScene(new Scene(root));
primaryStage.setTitle("Memory Test");
primaryStage.show();
}
//-------------------------------------------------
//Getter for the event handler
public static EventHandler<MouseEvent> gameController() {
return handler;
}
//-------------------------------------------------
//Getter, Setter and "resetter" for the index
public static void resetIndex() { index = 0; }
public static int getIndex() { return index; }
public static void setIndex(int i) {
index = i;
}
//-------------------------------------------------
}
控制器:Controller.java
package memory;
import javafx.event.EventHandler;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.input.MouseEvent;
public class Controller implements EventHandler<MouseEvent>{
//-------------------------------------------------
@Override
public void handle(MouseEvent event) {
//Get the card which cas clicked on
Card card = (Card) event.getSource();
//If the card was already open, don't do anything
if (!Main.isOpen[card.getRow()][card.getColumn()]) {
//Open the card
card.openCard();
//We opened the first card of the turn
if (Main.getIndex() == 0) {
//Set the card as open
Main.isOpen[card.getRow()][card.getColumn()] = true;
//Remember the index
Main.setIndex(Main.indexArray[card.getRow()][card.getColumn()]);
System.out.println("index: "+Main.getIndex());
//We opened the second card
}else if (Main.getIndex() != 0) {
//Check if it is a pair
if (Main.getIndex() == Main.indexArray[card.getRow()][card.getColumn()]) {
//Decrement the number of pairs
Main.pairs--;
//Open the second card
Main.isOpen[card.getRow()][card.getColumn()] = true;
//Reset the index
Main.resetIndex();
}else{ //Close both cards if it isn't a pair
//Wait 0.7 second to let the player remember the cards
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
//Close the current card
card.closeCard();
System.out.println("index : " + Main.indexArray[card.getRow()][card.getColumn()]);
Main.isOpen[card.getRow()][card.getColumn()] = false;
//Close the first opened card by looking at the index
//It closes both cards with the same index, but it doesn't matter
//as the pair hasn't been found anyway
for (int i = 0; i < Main.indexArray.length; i++) {
for (int j = 0; j < Main.indexArray[0].length; j++) {
if (Main.getIndex() == Main.indexArray[i][j]) {
Main.cardArray[i][j].closeCard();
System.out.println("index: " + Main.indexArray[i][j]);
Main.isOpen[i][j] = false;
}
}
}
//Reset the index of last opened card
Main.resetIndex();
}
}
}
//Check endgame
if (Main.pairs == 0) {
//Show a dialog box
Alert incorrectPairs = new Alert(AlertType.INFORMATION);
incorrectPairs.setTitle("GAME OVER");
incorrectPairs.setHeaderText("The game is over");
incorrectPairs.setContentText("You found all the pairs, congrats!");
incorrectPairs.showAndWait();
}
}
//-------------------------------------------------
}
答案 0 :(得分:1)
您正在使用Thread.sleep(...)
阻止UI线程。这可以防止任何待处理的更改被重新绘制,因此您根本看不到第一个更新;暂停完成后,您只能看到后续更新。
在UI线程上实现暂停的最简单方法是使用JavaFX动画API中的PauseTransition
。基本上,你做
PauseTransition pause = new PauseTransition(Duration.millis(700));
pause.setOnFinished(e -> {
// code to execute after pause...
});
pause.play();
在您的情况下,您可能想要禁用用户界面,因此用户在暂停期间无法点击任何内容,因此您可以执行类似
的操作PauseTransition pause = new PauseTransition(Duration.millis(700));
pause.setOnFinished(e -> {
card.closeCard();
// ... etc...
card.getParent().setDisable(false);
});
card.getParent().setDisable(true);
pause.play();