javafx animationtimer未正确停止

vof42yt1  于 2021-07-03  发布在  Java
关注(0)|答案(2)|浏览(400)

所以,我用javafx创建了一个snake游戏,我似乎无法让游戏正确地暂停,也就是说,它偶尔暂停,其他时候,游戏只是忽略了暂停。所以,基本上我有一个 Main 类初始化所有gui组件,它还充当javafx应用程序的控制器。
我有一个 Button 命名 gameControl 它启动/暂停游戏,一个变量 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 函数如下所示:

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` 类的变量,允许从其他函数调用。
以及 `pauseGame` 功能:

void pauseGame() {
paused = true;
gameLoop.stop();
}

所以,正如我在比赛前所说的,我不会每次击球都暂停 `gameControl` 我怀疑是因为 `Thread.sleep(30);` 管道内的管线 `Task` 的 `gameLoop` . 尽管如此,我仍然不完全确定,也不知道如何解决这个问题。任何帮助都将不胜感激。
0kjbasz6

0kjbasz61#

你的直觉 Thread.sleep(30); 可能是导致问题的原因,但问题正在正确的轨道上。用户可以单击按钮调用 pauseGame ,将paused设置为true,并告诉gameloop停止。如果新的sleeper线程在那一刻启动并休眠,它将调用 start() 当它醒来时在游戏循环中。
一种选择可能是简单地检查 paused 在sleeper任务中确定是否应该启动gameloop。

Task<Void> sleeper = new Task<>(){
    @Override
    protected Void call() throws Exception {
        gameLoop.stop();
        Thread.sleep(30);
        if (!paused) {
            gameLoop.start();
        }
        return null;
    }
};

假设正在设置暂停值并从多个线程读取,我建议添加一个机制以确保不会出现不确定的行为。将布尔值替换为原子布尔值是确保一致性的直接选择。

ttisahbt

ttisahbt2#

什么类型的“暂停”?检查它是否为null,然后将其视为布尔值。。我不明白为什么它会是一个大的“b”布尔对象 Package 器而不是原始的布尔类型。
这是:

//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;
            }
        };

是一个绝对可怕的方法来控制速度。让你的游戏循环运行,检查每个循环的时间,看看是否有足够的时间,你应该更新的东西。你的动画定时器将驱动游戏。您不想暂停主平台线程,也不想暂停正在处理任务的任何工作线程。如果要安排任务,请将它们安排为按所需的时间间隔运行—不要在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;
        }

你甚至可以做一个循环来“追赶”,以防动画计时器由于某种原因而落后:

while ((now - lastTime) > updateIterval) {
            drawSnake(); //draws the snake on the game
            snake.move(); //move snake ahead
            lastTime += updateIterval;
        }

相关问题