为啥游戏循环渲染的次数多于更新的次数
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 游戏,滑动时它通过循环的次数超过了它应该的次数,并命中了已经改变的测试/更改数字