Java2D 游戏随机卡顿。我究竟做错了啥?

Posted

技术标签:

【中文标题】Java2D 游戏随机卡顿。我究竟做错了啥?【英文标题】:Java2D game stutters randomly. What am I doing wrong?Java2D 游戏随机卡顿。我究竟做错了什么? 【发布时间】:2018-02-01 16:49:02 【问题描述】:

我目前正在使用 Swing 组件开发 2D 游戏。 每次我运行我的游戏时,它都会在某些时候随机出现口吃。这是我的游戏循环代码:

public class FixedTSGameLoop implements Runnable

    private MapPanel _gamePanel;

    public FixedTSGameLoop(MapPanel panel)
    
        this._gamePanel = panel;
    

    @Override
    public void run()
    
        long lastTime = System.nanoTime(), now;
        double amountOfTicks = 60.0;
        double amountOfRenders = 120.0;
        double nsTick = 1000000000 / amountOfTicks;
        double nsRender = 1000000000 / amountOfRenders;
        double deltaTick = 0;
        double deltaRender = 0;
        while (this._gamePanel.isRunning())
        
            now = System.nanoTime();
            deltaTick += (now - lastTime) / nsTick;
            deltaRender += (now - lastTime) / nsRender;
            lastTime = now;
            while (deltaTick >= 1)
            
                tick();
                deltaTick--;
            
            while (deltaRender >= 1)
            
                render();
                deltaRender--;
            
        
    

    private void tick()
    
        /**
         * Logic goes here:
         */
        this._gamePanel.setLogic();
    

    private void render()
    
        /**
         * Rendering the map panel
         */
        this._gamePanel.repaint();
    

我多次尝试省略某些代码部分,认为它们会导致延迟,但我没有发现任何特别导致它的原因,所以我认为问题出在我的游戏循环机制上。 感谢您的帮助!

【问题讨论】:

从另一个线程对 Swing 方法(包括repaint)的任何调用都需要在 EDT 上使用SwingUtilities.invokeLater 方法完成。 嗯,你能给我一个关于我的代码的例子吗?游戏循环的其他方面还好吗? SwingUtilities.invokeLater( () -> _gamePanel.repaint() ); 为其中之一。您可能还需要对 _gamePanel.setLogic(); 执行相同的操作。 同样的问题依然存在... Each time I run my game it stutters randomly at some points. - 你有一个不断执行的 while 循环。游戏应该在某个时间间隔进行,以便 CPU 有机会休息。所以,你应该使用Swing Timer 来安排你想要的时间间隔玩游戏。 【参考方案1】:

您的游戏循环必须包含“Thread.sleep”,以便在尊重您的目标 FPS 所需的时间内休眠。

主循环应该包含 1 个 tick() 和 1 个 render()。

您当前的实现正在淹没绘制管理器,当底层缓冲区已满以及垃圾收集器将完成其工作时会出现减速。

【讨论】:

但是代码只有在“deltaRender”变量达到1的值时才调用render方法,这意味着距离上次调用已经过去了1000/120毫秒(与逻辑设置相同,但为1000/60 毫秒)。 当然,但你的主进程却在 100% 消耗 CPU 核心。使用 sleep()。 需要更多详细信息?见gameprogrammingpatterns.com/game-loop.html 我明白了。我只是在循环结束时调用了 Thread.Sleep(1),它现在就像一个魅力。谢谢!【参考方案2】:

虽然您将渲染和逻辑拆分为两种不同的方法很好,但问题在于它们存在于同一个线程中。

减少延迟需要做的是将它们放在单独的线程中。渲染线程将从逻辑线程请求当前状态的快照(以防止并发修改)并渲染该快照。

现在,如果一个渲染耗时过长,或者一个逻辑步骤耗时过长,则另一项检查将不得不等待它完成才能开始工作。

【讨论】:

以上是关于Java2D 游戏随机卡顿。我究竟做错了啥?的主要内容,如果未能解决你的问题,请参考以下文章

“多重定义”错误。我究竟做错了啥?

我究竟做错了啥?角垫形式场

我究竟做错了啥? NSFileManager 问题

抛出“密钥不存在”异常。我究竟做错了啥?

文件不会写入磁盘。我究竟做错了啥?

我究竟做错了啥?使用 lxml 解析 HTML