Unity3D :重要的类-时间

推荐:将NSDT场景编辑器加入你的3D工具链
3D工具集:NSDT简石数字孪生
重要的类-时间
Unity 的 Time 类提供了重要的基本属性,允许您在项目中处理与时间相关的值。
本页包含 Time 类中一些更常用成员的说明,以及它们之间的关系。您可以在时间脚本参考页面上阅读时间类每个成员的单独描述。
Time 类具有一些属性,这些属性为你提供数值,使你能够测量游戏或应用运行时经过的时间。例如:
Time.time
返回自项目开始播放以来的时间量(以秒为单位)。Time.deltaTime
返回自上一帧完成以来经过的时间量(以秒为单位)。此值因游戏或应用运行的每秒帧数 (FPS) 速率而异。
Time 类还为您提供了一些属性,允许您控制和限制时间的流逝方式,例如:
Time.timeScale
控制时间流逝的速率。您可以读取此值,或将其设置为控制时间流逝的速度,从而允许您创建慢动作效果。Time.fixedDeltaTime
控制 Unity 固定时间步长循环的间隔(用于物理,如果要编写确定性的基于时间的代码)。Time.maximumDeltaTime
设置了引擎报告为已通过上述“增量时间”属性的时间量的上限。
可变和固定时间步长
Unity 有两个跟踪时间的系统,一个在每个步骤之间具有可变的时间量,另一个在每个步骤之间具有固定的时间量。
可变时间步长系统在将帧绘制到屏幕上的重复过程上运行,并在每帧运行一次应用或游戏代码。
固定时间步长系统每一步以预定义的量向前步,并且不链接到可视帧更新。它通常与物理系统相关联,物理系统以固定时间步长指定的速率运行,但如有必要,您也可以在每个固定时间步长执行自己的代码。
可变帧速率管理
游戏或应用的帧速率可能会因显示和执行每帧代码所需的时间而异。这受运行它的设备的功能的影响,也受显示的图形和每帧所需的计算的不同复杂性的影响。例如,与只有一个字符时相比,当屏幕上有100个活动字符时,游戏可能会以较慢的帧速率运行。这种可变速率通常称为“每秒帧数”或 FPS。
除非受质量设置或自适应性能包的限制,否则 Unity 会尝试以尽可能快的帧速率运行您的游戏或应用程序。您可以在标有“游戏逻辑”的部分中查看执行顺序图中每帧发生的情况的更多详细信息。
Unity 提供了 Update
方法作为入口点,供你每帧执行自己的代码。例如,在游戏角色的方法中,您可以从游戏手柄读取用户输入,并将角色向前移动一定量。在处理此类基于时间的操作时,请务必记住,游戏的帧速率可能会有所不同,因此更新调用之间的时间长度也会有所不同。Update
考虑逐渐向前移动对象的任务,一次一帧。乍一看,您似乎只需将对象平移每帧固定的距离:
//C# 脚本示例
using UnityEngine;
using System.Collections;
public class ExampleScript : MonoBehaviour {
public float distancePerFrame;
void Update() {
transform.Translate(0, 0, distancePerFrame); // 这不正确
}
}
但是,使用此代码时,随着帧速率的变化,对象的表观速度也会变化。如果游戏以每秒 100 帧的速度运行,则对象每秒移动距离每帧 100 次。但是,如果帧速率减慢到每秒 60 帧(例如由于 CPU 负载),那么它每秒只会向前移动 60 次,因此在相同的时间内覆盖更短的距离。
在大多数情况下,这是不可取的,尤其是对于游戏和动画。无论帧速率如何,都希望游戏内对象以稳定且可预测的速度移动更为常见。解决方案是按每帧经过的时间量缩放每帧的移动量,您可以从 Time.deltaTime 属性中读取该时间:
//C# 脚本示例
using UnityEngine;
using System.Collections;
public class ExampleScript : MonoBehaviour {
public float distancePerSecond;
void Update() {
transform.Translate(0, 0, distancePerSecond * Time.deltaTime);
}
}
请注意,移动现在以距离PerSecond而不是距离PerFrame给出。随着帧速率的变化,移动步骤的大小也会相应变化,因此对象的速度将是恒定的。
根据您的目标平台,使用 Application.targetFrameRate 或 QualitySettings.vSyncCount 来设置应用程序的帧速率。有关更多信息,请参阅 Application.targetFrameRate API 文档。
固定时间步长
与主帧更新不同,Unity 的物理系统在固定的时间步长下工作,这对于模拟的准确性和一致性非常重要。在每一帧开始时,Unity 会根据需要执行尽可能多的固定更新,以赶上当前时间。您可以在标有“物理”的部分的执行顺序图中查看固定更新周期中发生的情况的更多详细信息。
如有必要,您还可以与固定时间步同步执行自己的代码。这最常用于执行您自己的物理相关代码,例如向刚体施加力。Unity 提供了 FixedUpdate
方法作为入口点,以便您在每个固定时间步执行自己的代码。
fixedDeltaTime
属性控制 Unity 的固定时间步长循环的间隔,并以秒为单位指定。例如,值 0.01 表示每个固定时间步长的持续时间为百分之一秒,因此每秒将有 100 个固定时间步长。
如果你的游戏或应用的运行帧速率高于每秒固定时间步长的数量,则意味着每个帧持续时间小于单个固定时间步长的持续时间。在这种情况下,Unity 每帧执行零个或一个固定的物理更新。例如,如果固定时间步长值为 0.02,则每秒将有 50 个固定更新。如果您的游戏或应用随后以每秒 60 帧的速度运行,则大约十分之一的帧不会有固定更新。
如果您的游戏或应用的运行帧速率低于固定时间步长值,则意味着每个帧持续时间都长于单个固定时间步长。为了解决这个问题,Unity 将在每一帧执行一次或多次固定更新,以便物理模拟赶上自最后一帧以来经过的时间量。例如,如果固定时间步长值为 0.01,则每秒将有 100 个固定更新。如果应用以每秒 25 帧的速度运行,则“直到”每帧执行四次固定更新。您可能想要这样的场景,其中建模更准确的物理场比具有高帧速率更重要。
可以在“时间”窗口中读取或更改固定时间步的持续时间,也可以使用 Time.fixedDeltaTime 属性从脚本中读取或更改。
注意:较低的时间步长值意味着更频繁的物理更新和更精确的模拟,从而导致更高的 CPU 负载。
Unity 的时间逻辑
以下流程图说明了 Unity 用于计算单个帧中时间的逻辑,以及 time、deltaTime、fixedDeltaTime 和 maximumDeltaTime 属性如何相互关联。

控制和处理时间变化
如上所述,每帧之间经过的时间量可能会有所不同。
经过的时间变化可能很小。例如,在以每秒 60 帧运行的游戏中,每秒的实际帧数可能会略有不同,因此每帧持续 0.016 到 0.018 秒。当你的应用执行大量计算或垃圾回收时,或者当保持帧速率所需的资源正被其他应用使用时,可能会出现较大的变化。
本节中介绍的属性包括:
- 时间.时间
- 时间.未缩放时间
- 时间.三角洲时间
- Time.unscaledDeltaTime
- 时间.平滑三角洲时间
- 时间.时间尺度
- 时间.最大增量时间
这些属性都有自己的脚本 API 文档页,但查看它们之间的说明和输出有助于了解它们的适当用法。
Time.time
表示自玩家开始以来经过的时间量,因此通常会持续稳定地上升。 表示自最后一帧以来经过的时间量,因此理想情况下保持相当恒定。Time.deltaTime
这两个值都是对应用或游戏中所用时间的主观度量。这意味着它们会考虑您应用的任何时间缩放。例如,您可以将 Time.timeScale 设置为 0.1 以获得慢动作效果(表示正常播放速度的 10%)。在这种情况下,报告的值以“实时”速率的 10% 增加。10 秒后,的值将增加 1。除了减慢或加快应用中的时间之外,还可以将 Time.timeScale 设置为零以暂停游戏,在这种情况下,仍会调用该方法,但根本不会增加,并且为零。Time.timeTime.timeUpdateTime.timeTime.deltaTime
这些值也受属性值的限制。这意味着这些属性报告的任何暂停或帧速率变化的长度永远不会超过最大增量时间。例如,如果发生一秒的延迟,但最大 DeltaTime 设置为默认值 0.333,则只会增加 0.333,并且等于 0.333,尽管现实世界中实际经过了更多时间。Time.maximumDeltaTimeTime.timeTime.deltaTime
每个属性(和)的未缩放版本忽略了这些主观变化和限制,并报告了两种情况下经过的实际时间。这对于任何应该以固定速度响应的内容都很有用,即使游戏以慢动作播放也是如此。这方面的一个例子是 UI 交互动画。Time.unscaledTimeTime.unscaledDeltaTime
下表显示了 16 帧一个接一个过去的示例,在单个帧上出现一个大的延迟。这些图说明了各种时间类属性如何报告和响应帧速率的这种巨大变化。
框架 | 未缩放时间 | 时间 | 未缩放的增量时间 | 三角洲时间 | 平滑三角洲时间 |
---|---|---|---|---|---|
1 | 0.000 | 0.000 | 0.018 | 0.018 | 0.018 |
2 | 0.018 | 0.018 | 0.018 | 0.018 | 0.018 |
3 | 0.036 | 0.036 | 0.018 | 0.018 | 0.018 |
4 | 0.054 | 0.054 | 0.018 | 0.018 | 0.018 |
5 | 0.071 | 0.071 | 0.017 | 0.017 | 0.018 |
6 | 0.089 | 0.089 | 0.018 | 0.018 | 0.018 |
7 | 0.107 | 0.107 | 0.018 | 0.018 | 0.018 |
8 (a) | 1.123 (乙)) | 0.440 (c) | 1.016 (d) | 0.333(和) | 0.081 (华氏度)) |
9 | 1.140 | 0.457 | 0.017 | 0.017 | 0.066 |
10 | 1.157 | 0.474 | 0.017 | 0.017 | 0.056 |
11 | 1.175 | 0.492 | 0.018 | 0.018 | 0.049 |
12 | 1.193 | 0.510 | 0.018 | 0.018 | 0.042 |
13 | 1.211 | 0.528 | 0.018 | 0.018 | 0.038 |
14 | 1.229 | 0.546 | 0.018 | 0.018 | 0.034 |
15 | 1.247 | 0.564 | 0.018 | 0.018 | 0.031 |
16 | 1.265 | 0.582 | 0.018 | 0.018 | 0.028 |
第 1 帧到第 7 帧以大约每秒 60 帧的稳定速率运行。您可以看到“time”和“unscaledTime”一起稳步增加,表明此示例中的时间刻度设置为 1。
然后在第 8 帧 (a) 上,发生刚好超过一秒的大延迟。当存在资源竞争时,可能会发生这种情况。例如,应用程序中的代码在从磁盘加载大量数据时阻止主进程。
当帧延迟大于最大增量时间值时,Unity 会限制 报告的值以及添加到当前 .此限制的目的是避免在时间步长超过该量时可能发生的不良副作用。如果没有限制,则在帧速率峰值期间,通过 deltaTime 缩放移动的对象将能够在游戏中穿过墙壁“毛刺”,因为理论上对象从一帧移动到下一帧的距离没有限制,因此它可能可以在单个帧中从障碍物的一侧跳到另一侧,而不会与它相交。deltaTimetime
可以在“时间”窗口中调整最大增量时间值(该值标记为“允许的最大时间步长”),也可以使用 Time.maximumDeltaTime 属性进行调整。
默认的最大值增量时间值为三分之一秒 (0.33333333)。这意味着,在由 deltaTime 控制的移动游戏中,对象从一帧到下一帧的移动仅限于它在三分之一秒内可以覆盖的距离,而不管自上一帧以来实际经过了多少时间。
以图形形式查看上表中的数据有助于可视化这些时间属性之间的关系:

你可以在上面的第8帧看到,(d)和(e)在他们报告的时间上有所不同。尽管在第 7 帧和第 8 帧之间经过了整整一秒的实时时间,但 deltaTime 仅报告 0.333 秒。这是因为 deltaTime 被限制在该值上。unscaledDeltaTimedeltaTimemaximumDeltaTime

同样,(b)增加了大约整整一秒,因为增加了真正的(未钳夹)值,而(c)只增加了较小的钳位值。该值不会赶上已过的实际时间量,而是表现得好像延迟只是持续时间。unscaledTimetimetimemaximumDeltaTime

该属性报告最近的 deltaTime 值的近似值,并根据算法平滑了所有变化。这是避免不必要的大步长或运动或其他基于时间的计算的波动的另一种技术。特别是那些低于 设定的阈值的那些。平滑算法无法预测未来的变化,但它会逐渐调整其报告值以平滑最近经过的增量时间值的变化,以便平均报告时间大致等于实际经过的时间量。Time.smoothDeltaTimemaximumDeltaTime
时间变化和物理系统
该值也会影响物理系统。物理系统使用该值来确定每个步骤的仿真时间。Unity 会尝试使物理模拟与经过的时间保持同步,如上所述,有时会每帧执行多个物理场更新。但是,如果物理模拟落后太远,例如由于一些繁重的计算或某种延迟,物理系统可能需要大量的步骤才能赶上当前时间。如此大量的步骤本身可能会导致进一步的减速。maximumDeltaTimefixedTimestep
为了避免这种由于试图赶上而减速的循环反馈,最大 DeltaTime 值还充当物理系统在任何给定两帧之间模拟的时间量的限制。
如果帧更新的处理时间超过最大增量时间,则物理引擎不会尝试模拟超出最大增量时间的任何时间,而是让帧处理赶上。帧更新完成后,物理效果将恢复,就好像自停止以来没有经过任何时间。这样做的结果是,物理对象不会像往常那样实时完美地移动,而是会稍微减慢速度。然而,物理“时钟”仍然会跟踪它们,就好像它们在正常移动一样。物理时间的减慢通常并不明显,并且通常是与游戏性能的可以接受的权衡。
时间尺度
对于慢动作等特殊时间效果,有时放慢游戏时间的流逝速度很有用,以便代码中的动画和基于时间的计算以较慢的速度进行。此外,您有时可能希望完全冻结游戏时间,例如游戏暂停时。Unity 具有“时间刻度”属性,用于控制游戏时间相对于实时时间的速度。如果您将比例设置为 1.0,则您的游戏内时间与实时匹配。值 2.0 会使 Unity 中时间流逝的速度提高一倍(即,动作将加快),而值 0.5 会将游戏速度减慢到一半。值为零将使您的游戏时间完全停止。请注意,时间刻度实际上并没有减慢执行速度,而是使用 Time.deltaTime 和 Time.fixedDeltaTime 更改报告给更新和固定更新函数的时间步长。当您减少时间刻度时,可能会同样频繁地调用更新函数,但每帧的 deltaTime 值会更少。其他脚本函数不受时间刻度的影响,因此例如,您可以在游戏暂停时显示具有正常交互的 GUI。
“时间”窗口有一个属性,可用于全局设置时间刻度,但使用 ScriptRef:Time-timeScale 属性从脚本设置值通常更有用:
//C# 脚本示例
using UnityEngine;
using System.Collections;
public class ExampleScript : MonoBehaviour {
void Pause() {
Time.timeScale = 0;
}
void Resume() {
Time.timeScale = 1;
}
}
捕获帧速率
时间管理的一个特例是您想将游戏玩法录制为视频。由于保存屏幕图像的任务需要相当长的时间,因此游戏的正常帧速率会降低,并且视频无法反映游戏的真实性能。
若要改善视频的外观,请使用“捕获帧速率”属性。该属性的默认值为 0,表示未记录的游戏玩法。用于录制。将属性的值设置为零以外的任何值时,游戏时间会减慢,并且帧更新会以精确的定期间隔发出。帧之间的间隔等于 ,因此如果将该值设置为 5.0,则每五分之一秒进行一次更新。随着对帧速率的要求有效降低,您有时间在更新功能中保存屏幕截图或采取其他操作:1 / Time.captureFramerate
//C# script example
using UnityEngine;
using System.Collections;
public class ExampleScript : MonoBehaviour {
// Capture frames as a screenshot sequence. Images are
// stored as PNG files in a folder - these can be combined into
// a movie using image utility software (eg, QuickTime Pro).
// The folder to contain our screenshots.
// If the folder exists we will append numbers to create an empty folder.
string folder = "ScreenshotFolder";
int frameRate = 25;
void Start () {
// Set the playback frame rate (real time will not relate to game time after this).
Time.captureFramerate = frameRate;
// Create the folder
System.IO.Directory.CreateDirectory(folder);
}
void Update () {
// Append filename to folder name (format is '0005 shot.png"')
string name = string.Format("{0}/{1:D04} shot.png", folder, Time.frameCount );
// Capture the screenshot to the specified file.
Application.CaptureScreenshot(name);
}
}
使用这种技术可以改善视频,但会使游戏更难玩。尝试不同的 Time.captureFramerate 值以找到良好的平衡。
由3D建模学习工作室整理翻译,转载请注明出处!