为啥游戏循环渲染的次数多于更新的次数

Posted

技术标签:

【中文标题】为啥游戏循环渲染的次数多于更新的次数【英文标题】:Why gameloops render more times than updating为什么游戏循环渲染的次数多于更新的次数 【发布时间】:2019-08-29 12:23:21 【问题描述】:

许多游戏循环使用滴答和渲染,每 X 毫秒完成一次滴答并尽可能渲染。为什么不打勾然后渲染? 在我看来,在滴答声之间渲染将绘制相同的东西,那么为什么要多次调用它呢? (如果不解释为什么请)

典型的游戏循环是:

public void run() 

        long lastTime = System.nanoTime();
        double amountOfTicks = 60.0;
        double nsBetweenTicks = 1000000000 / amountOfTicks;
        double delta = 0;
        long timer = System.currentTimeMillis();
        while(running)
            long now = System.nanoTime();
            delta += (now - lastTime) / nsBetweenTicks;
            lastTime = now;
            while(delta >=1)
                tick();
                delta--;
            
            render();
       

我的问题是为什么不:

public void run() 

        long lastTime = System.nanoTime();
        double amountOfTicks = 60.0;
        double nsBetweenTicks = 1000000000 / amountOfTicks;
        double delta = 0;
        long timer = System.currentTimeMillis();
        while(running)
            long now = System.nanoTime();
            delta += (now - lastTime) / nsBetweenTicks;
            lastTime = now;
            while(delta >=1)
                tick();
                render();
                delta--;
            
       

【问题讨论】:

while 循环可以让滴答声赶上经过的时间。通过这种方式,对象以真实的速度移动,即使出于某种原因,UI 无法为每个刻度进行渲染。由于包括渲染在内的整个循环太慢而试图在这里追赶,如果您每次都在追赶循环中渲染,您可能永远赶不上。 @Erwin 说得好,但如果游戏更新多次,然后图像才发生变化(与之前的图像相比发生巨大变化),这不是一件坏事吗?如果我不能同时勾选和渲染,也许我应该降低 fps。此外,在大多数情况下,我可以在每秒 60 次的情况下渲染 150-200 次。即使在这种情况下,我也不应该一起勾选和渲染? 我不知道它背后的理论,但我认为如果物体移动缓慢,大多数人会感知到更好的体验。如果有一个很大的差距(也许 Java 做了一个非常大的垃圾收集)它可能会成为一个问题(如果你愿意,你可以检查差距是否变得太大)但大多数情况下只会有几个跳过的渲染帧(除非你的帧率太高),用户仍然会觉得流畅。 【参考方案1】:

游戏逻辑不应与帧率绑定。

有些游戏不使用每秒 60 个滴答声,有些游戏(如 Minecraft)以每秒 20 个滴答声运行。这将有效地将游戏锁定在 20 fps。

即使所有游戏都以每秒 60 个滴答的速度运行,如果有人拥有 144 Hz 显示器会怎样?他会被卡在 60 fps 的播放速度。

如果您渲染游戏的频率高于滴答声,您仍然可以在渲染逻辑中运行动画和其他内容,而无论游戏逻辑停止多久,即使它的滴答声频率也会使游戏流畅比显示器的刷新率慢。

【讨论】:

显然我不理解“更新”的概念。在 Minecraft 中,更新做什么?开启播放器视图是在render方法上吗? 计算游戏逻辑的时间是一个滴答声。以 Minecraft 为例,它可以是任何东西,从开门到方块破坏再到红石电路更新。为了更加流畅,玩家视图与刻度分离。【参考方案2】:

tick 和 render 方法有什么作用?

    勾选(或更新,但我更喜欢勾选)方法只是更新游戏对象的状态。例如,它更新玩家坐标、处理输入、检查当前状态(菜单、游戏、暂停)并更新它等等。 渲染方法只是将它绘制到屏幕上。它就像一个画家,根据感觉来画东西。但在我们的案例中,他基于一些变量和其他信息。

他们是如何工作的?

    Tick 方法每秒更新特定次数(例如,20、60 等)。我称这个数字为 UPS(代表每秒更新)。让我们考虑一下玩家的移动。他的速度是每秒 20 像素。因此,如果我们想以这种速度移动播放器,我们需要了解 UPS。例如,UPS 是 20。所以我们的播放器每刻将移动 20 个像素。这是错误的。如果是我们的 20 个滴答声,那么在 1 秒内,我们的玩家将移动 20*20 像素(每秒 400 像素)。所以我们播放器的速度将是每刻 20 * (1 / UPS)。我们可以改变我们的 UPS 并且每刻玩家移动的像素数也会改变。但他仍会每秒移动 20 个像素。为了清楚起见,假设我们的 UPS 为 1,这意味着每秒一个滴答声。那么速度将是 20 * (1 / 1) = 20 像素每刻(一秒是一个刻)= 30 像素每秒。和我们想要的一样。 渲染只是绘制我们更新的内容。它可以以与我们更新相同的速度完成,我也可以更快地完成。但这没关系,因为我们只会看到我们更新的内容。 UPS 可以是 1,但 FPS 是 160。你会看到每一秒都在移动。但这并不意味着我们每秒渲染 1 次,而是意味着我们在一秒钟内渲染同一张图片。 1 秒后我们更新游戏,我们将看到另一张图片。

回答你的问题,你可以一起使用 tick() 和 render()。

【讨论】:

以上是关于为啥游戏循环渲染的次数多于更新的次数的主要内容,如果未能解决你的问题,请参考以下文章

制作一个 java 2048 游戏,滑动时它通过循环的次数超过了它应该的次数,并命中了已经改变的测试/更改数字

Rx 中的游戏更新渲染循环:如何确保一致的状态?

React 限制渲染次数以防止无限循环...重新渲染次数过多

游戏循环帧独立

在 Java 游戏中渲染比更新更快有啥好处?

跳跃游戏--DP和贪心策略