[英]JavaFX AnimationTimer not stopping properly
因此,我正在使用 JavaFX 创建贪吃蛇游戏,但我似乎无法正确暂停游戏,即它偶尔会暂停,有时游戏会忽略暂停。 所以,基本上我有一个Main
的 class 来初始化所有的 GUI 组件,它还充当 javafx 应用程序的 controller。
我有一个名为gameControl
的Button
,它启动/暂停游戏,一个变量Boolean pause
跟踪游戏状态(新/暂停/运行),以及方法startGame
, pauseGame
。
gameControl
按钮的EventHandler
如下:
gameControl.setOnClicked(event->{
if(paused == null) startGame(); //new game
else if(paused) continueGame(); //for paused game
else pauseGame(); //for running game
});
startGame
function 看起来像这样:
void startGame(){
paused = false;
Snake snake = new Snake(); //the snake sprite
//following gameLoop controls the animation of the snake
gameLoop = new AnimationTimer(){
@Override
public void handle(long now){
drawSnake(); //draws the snake on the game
snake.move(); //move snake ahead
//following code is for slowing down the gameLoop renders to make it easier to play
Task<Void> sleeper = new Task<>(){
@Override
protected Void call() throws Exception {
gameLoop.stop();
Thread.sleep(30);
gameLoop.start();
return null;
}
};
new Thread(sleeper).start();
//force garbage collection or else throws a bunch of exceptions after a while of running.
//not sure of the cause...
System.gc();
}
};
gameLoop.start();
}
AnimationTimer gameLoop
是 class 的变量,允许从其他函数调用。
以及暂停游戏pauseGame
:
void pauseGame() {
paused = true;
gameLoop.stop();
}
所以,正如我之前所说,每次我点击gameControl
按钮时游戏都不会暂停,我怀疑这是由于Thread.sleep(30);
gameLoop
的Task
内的行。 话虽如此,我仍然不完全确定,也不知道如何解决这个问题。 任何帮助,将不胜感激。
什么类型是“暂停”? You check it for null, but then treat it as a boolean.. I can't understand why it would be a big 'B' Boolean object wrapper instead of the primitive boolean type.
这个:
//following code is for slowing down the gameLoop renders to make it easier to play
Task<Void> sleeper = new Task<>(){
@Override
protected Void call() throws Exception {
gameLoop.stop();
Thread.sleep(30);
gameLoop.start();
return null;
}
};
是一种绝对可怕的限制速度的方法。 让你的游戏循环运行,检查每个循环的时间,看看是否有足够的时间过去,你应该更新东西。 您的 animation 计时器将驱动游戏。 您不想暂停主平台线程,也不想暂停任何正在处理任务的工作线程。 如果您正在安排任务,请将它们安排在您想要的时间间隔运行 - 不要在 call() 方法中限制线程。
你真正想要的是这样的:
//following gameLoop controls the animation of the snake
gameLoop = new AnimationTimer(){
@Override
public void handle(long now){
if ((now - lastTime) > updateIterval) {
drawSnake(); //draws the snake on the game
snake.move(); //move snake ahead
lastTime = now;
}
如果 Animation 计时器由于某种原因落后,您甚至可以创建一个循环来“赶上”:
while ((now - lastTime) > updateIterval) {
drawSnake(); //draws the snake on the game
snake.move(); //move snake ahead
lastTime += updateIterval;
}
你的直觉是Thread.sleep(30);
可能导致问题是在正确的轨道上。 用户可以单击调用pauseGame
的按钮,将 paused 设置为 true,并告诉游戏循环停止。 如果新的睡眠线程在那个时候启动并进入睡眠状态,它会在游戏循环中调用start()
方法。
一种选择可能是简单地检查 sleeper 任务中paused
的值,以确定它是否应该启动游戏循环。
Task<Void> sleeper = new Task<>(){
@Override
protected Void call() throws Exception {
gameLoop.stop();
Thread.sleep(30);
if (!paused) {
gameLoop.start();
}
return null;
}
};
鉴于暂停的值是从多个线程中设置和读取的,我建议添加一种机制来确保您不会获得不确定的行为。 将 Boolean 交换为AtomicBoolean是确保一致性的直接选项。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.