编辑:找到答案!尽管CAG确实让我走上正轨,但我会奖励他。我提供了正确的答案。
我正在使用Canvas在JavaFX中制作Snake游戏。
我让游戏在一个循环中运行:
问题是,如果我使用Thread.sleep(),我的画布根本不会加载。然而,在幕后,游戏仍在运行,直到我撞墙而死。
我在这里做错了吗? thread.sleep()是否暂停了加载和显示JavaFX节点的能力?
Thread gameThread = new Thread() {
@Override
public synchronized void start() {
super.start();
printGridToGUI();
while (KEEP_PLAYING) {
generateNextGrid();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(SnakeGUIController.class.getName()).log(Level.SEVERE, null, ex);
}
Platform.runLater(() -> {
printGridToGUI();
});
}
/*Stop continuing to play. You either won or lost.*/
if (WON_GAME) {
System.out.println("Congratulations!");
} else {
System.out.println("You lose.");
}
}
};
gameThread.start();
其中printGrid()是:
/**
* Prints the grid, with chars in place of on and off areas.
*/
public void printGridToGUI() {
resetCanvas();
for (Coordinate c : coordinates) {
drawCell(c.row, c.col, true);
}
drawCell(food.row, food.col, true);
}
和resetCanvas是:
/**
* Clears the boolean array, setting all values to false. A quick way to
* wipe the grid.
*/
public final void resetCanvas() {
/*Lay out the grid on the canvas.*/
GraphicsContext gc = canvas.getGraphicsContext2D();
for (int row = 0; row < GRID_SIZE; row++) {
for (int col = 0; col < GRID_SIZE; col++) {
drawCell(row, col, false);
}
}
}
和drawCell是:
/**
* Draws a cell on the canvas at the specified row and col. The row, col
* coordinates are translated into x,y coordinates for the graphics context.
*
* @param row The row of the cell to paint.
* @param col The col of the cell to paint.
* @param cellON The state of the cell, if it is on or off.
*/
private void drawCell(int row, int col, boolean cellON) {
/*Translate the row, col value into an x-y cartesian coordinate.*/
int xCoord = 0 + col * CELL_SIZE;
int yCoord = 0 + row * CELL_SIZE;
/*Draw on the canvas.*/
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setFill(Color.BLACK);
gc.fillRect(xCoord, yCoord, CELL_SIZE, CELL_SIZE);
if (!cellON) {
gc.setFill(Color.WHITE);
int BORDER = 1;
gc.fillRect(xCoord + BORDER, yCoord + BORDER, CELL_SIZE - BORDER, CELL_SIZE - BORDER);
}
}
答案 0 :(得分:1)
我的猜测是你在FX应用程序线程上调用Thread.sleep()
。该线程负责保持您的UI响应,因此使其处于睡眠状态会冻结您的UI,同时让您的游戏机制处于响应状态(假设这些是从FX应用程序线程执行的)。
解决方案是在新线程中执行游戏循环,如下所示:
Thread gameLoop = new Thread(() ->
{
while (KEEP_PLAYING)
{
printGrid(); //<- I assume this prints the state of the grid to the console, and so is safe to execute off of the FX Application Thread
try
{
Thread.sleep(1000);
}
catch (InterruptedException ex) {}
Platform.runLater(() ->
{
generateNextGrid(); //<- execute this on the FX Application Thread as it modifies your UI
});
}
if (WON_GAME)
{
...
}
else
{
...
}
});
gameLoop.start();
这可以防止任何冻结,只要您没有执行任何长时间运行的任务或在FX应用程序线程上调用睡眠。
答案 1 :(得分:1)
想出来!我不得不使用JavaFX的并发包并利用Task而不是简单的Thread。
Task<Boolean> gameTask = new Task() {
@Override
protected Object call() throws Exception {
while (KEEP_PLAYING) {
generateNextGrid();
try {
Thread.sleep(GAME_SPEED_DELAY);
} catch (InterruptedException ex) {
Logger.getLogger(SnakeGUIController.class.getName()).log(Level.SEVERE, null, ex);
}
Platform.runLater(() -> printGridToGUI());
}
/*Stop continuing to play. You either won or lost.*/
if (WON_GAME) {
System.out.println("Congratulations!");
} else {
System.out.println("You lose.");
}
return true;
}
};
Thread gameThread = new Thread(gameTask);
gameThread.start();