use*_*021 3 language-agnostic game-engine game-physics
我正在尝试创建一款具有独立帧速率的游戏,其中myObject以每毫秒一个单位的速度向右移动。但是,我不知道如何deltaTime在这段代码中计算:
var currentTime = 0;
var lastTime = 0;
var deltaTime = 0;
while( play ) {
// Retrieve the current time
currentTime = Time.now();
deltaTime = currentTime - lastTime;
lastTime = currentTime;
// Move myObject at the rate of one unit per millisecond
myObject.x += 1 * deltaTime;
}
Run Code Online (Sandbox Code Playgroud)
假设第一帧花了 30 毫秒,所以deltaTime应该是 30,但它是 0,因为我们只知道帧开始的时间而不是帧结束的时间。然后,在第二帧中花费了 40 毫秒,因此deltaTime是 30,因此myObject.x是 30。但是,经过的时间是 70 毫秒(第一帧中的 30 毫秒 + 第二帧中的 40 毫秒),因此myObject.x应该是 70,而不是 30。
我不是在模拟物理,我只是想myObject相对于经过的时间(而不是帧)移动。
我该如何deltaTime正确计算?
我知道有些游戏引擎的人会使用大量的时间或滴答声,所以他们会提前制作动画。另外,我已经阅读了 Glenn Fiedler关于修复时间步长的文章和许多其他文章,但我仍然感到困惑。
尝试这个:
float LOW_LIMIT = 0.0167f; // Keep At/Below 60fps
float HIGH_LIMIT = 0.1f; // Keep At/Above 10fps
float lastTime = Time.now();
while( play ) {
float currentTime = Time.now();
float deltaTime = ( currentTime - lastTime ) / 1000.0f;
if ( deltaTime < LOW_LIMIT )
deltaTime = LOW_LIMIT;
else if ( deltaTime > HIGH_LIMIT )
deltaTime = HIGH_LIMIT;
lastTime = currentTime;
myObject.x += 1000 * deltaTime; // equivalent to one unit per ms (ie. 1000 per s)
}
Run Code Online (Sandbox Code Playgroud)
这有很多错误,但它更容易说明基本概念。
首先,请注意,您需要lastTime在循环开始之前使用某个值进行初始化。您可以使用较低的值(即 Time.now() - 33),以便第一帧产生所需的增量,或者像我一样使用它(您将看到我们在循环中限制它)。
接下来,您将在每个帧开始时获取当前时间,用它来计算自上次循环以来经过的时间(在该示例的第一次运行时为零)。然后我喜欢将其转换为秒,因为以“每秒”为单位比“每毫秒”更有意义 - 但请随意删除该/ 1000.0f部分以将其保留为毫秒。
然后您需要将 deltaTime 限制在某个可用范围(例如我使用 10-60fps,但您可以根据需要更改它)。这只是防止循环运行得太快或太慢。HIGH_LIMIT 特别重要,因为它可以防止非常大的增量值,这可能会导致游戏循环中的混乱(稍微不准确比让代码崩溃更好) - LOW_LIMIT 可以防止零(或非常小的)时间步长,这同样可以有问题(特别是对于物理)。
最后,计算完该帧的新deltaTime后,您可以保存当前时间以供下一帧使用。