我想让unity3D每隔n
毫秒调用一个函数 。我们将n
设置为20
。
创建一个全新的空白Unity3D项目。
将.Net version
更改为4
(文件>构建设置>播放器设置>其他设置>配置)
创建一个新脚本并添加以下内容:
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
private void FixedUpdate()
{
Debug.Log(sw.ElapsedMilliseconds);
sw.Restart();
}
点击播放。
你会看到你混合zeros, 29's and 30's
......
现在转到TimeManager
(编辑>项目设置>时间)
将Maximum Allowed Timestep
更改为匹配Fixed Timestep
(0.02)。
再次点击播放。
现在你会看到没有更多的零,但仍然在30ms左右。
我知道Unity中有Time.fixedDeltaTime
,但FixedUpdate
是否应该每20毫秒调用一次,而不是29/30毫秒?如果将TimeManager
中的所有属性设置为1,情况会更糟:现在我们看到大量(> 10ms)差异。
发生了什么事?为什么FixedUpdate
的调用晚于Unity3D所说的?
答案 0 :(得分:4)
首先,你不能在计算毫秒数时使用Debug.Log
方法,这个方法本身执行起来很慢,所以你应该创建一个保存在List
内的脚本时间,然后在控制台中打印它们。像这样:
using UnityEngine;
using System.Collections.Generic;
public class Fixedtest : MonoBehaviour {
List<long> myList = new List<long>();
System.Diagnostics.Stopwatch sw;
int i = 0;
bool hasCountFinished = false;
private void Start() {
Time.fixedDeltaTime = 0.02f;
QualitySettings.vSyncCount = 0;
sw = System.Diagnostics.Stopwatch.StartNew();
}
private void FixedUpdate() {
sw.Stop();
if (i<100) {
myList.Add(sw.ElapsedMilliseconds);
i++;
sw.Restart();
}
}
private void Update() {
if (!hasCountFinished && i>=100) {
hasCountFinished = true;
foreach (long myLong in myList) {
Debug.Log(myLong);
}
}
}
}
请注意,我设置了vSync
,这是为了告诉Unity NOT等待一个通常为16毫秒(60赫兹)的完整刷新周期,因此即使你在将fixedDeltaTime
设为0.2。
如果你使用这个脚本,你会发现列表中的大部分结果大约是20ms,显然由于引擎的其他组件会导致差异,执行时间为{{1等等。
修改强>
第一个结果(一些0然后是一个高于300毫秒的峰值)是由于Unity按下播放(序列化等)时所做的场景准备,它们完全正常,你可以&#39;做任何事情。
然后其他结果,正如我所说,取决于很多因素,即单行代码的执行时间,由于你的操作系统正在为Unity线程分配时间而可能会有所不同流程仍在运行。
请注意sw.Restart()
以这种方式运作:当您设置fixedDeltaTime
时,让我们假设您以{30}的刷新率保持vSync
。这意味着您希望物理引擎每20毫秒运行一次更新,无论您使用的是什么刷新率。
但是物理引擎在Unity的主游戏循环中运行,所以它可以执行零,每帧一次或多次执行。因此,在我们的示例中,会发生这种情况:
第1帧:修正更新,更新
游戏循环等待以完成单个刷新率,33ms。
第2帧:自上次固定更新以来已经过去了33ms,执行了一次固定更新和一次更新。
其他33毫秒等待。
第3帧:现在,自第一个帧以来,已经过了66ms,物理引擎应该从第2帧(66/20 = 3.3)更新三次,但直到现在它已执行只需一次,因此Unity将执行固定更新两次,以保持fixedDeltaTime = 0.2f
设置的一致性。
这就是为什么,当你在原始测试代码中保持fixedDeltaTime
时,你得到了那些结果,有时是16ms,有些则是33ms,因为16&lt; 20有时固定更新不会在单一游戏循环,但每两个游戏循环一次。