问题描述
伙计们,作为免责声明,我是编程的新手,所以如果我犯了一些非常明显的错误,请对我轻松一点
因此,我试图为我的游戏创建一个更高的可自定义倒数计时器,我希望它能够精确到0.01秒。我决定使用Coroutine方法创建计时器,而不是使用几次见过的增量时间计时器,并认为这将是一种更有效的方法。我的游戏不是很密集,因此每秒可以轻松运行数百帧,因此我认为使用Waitforseconds(0.01)会更好,因为每秒只需要调用100次,而不是数百次。但是,我的计时器遇到了主要问题。非常慢。我在Google和我的系统上并排运行了倒数计时器,从25秒开始,它比我的倒数时间快了10秒。我什至尝试过添加一个人为的延迟,以为waitforseconds函数超调了,所以当经过的时间少了一点时,我的时间就会减少0.01秒,但结果却有些不一致。这是我的代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TimerScript : MonoBehavIoUr
{
public Text textdisplay;
private double secondsLeft = 30;
public bool takingAway = false;
private string Texttodisplay;
public int Milisecondsdigits = 2;
void Start()
{
textdisplay = GetComponent<Text>();
Texttodisplay = "00:" + secondsLeft;
if(Milisecondsdigits == 0)
{
Milisecondsdigits = -1;
}
}
void Update()
{
if (takingAway == false && secondsLeft > 0)
{
StopAllCoroutines();
StartCoroutine(TimerTake());
}
if(Texttodisplay.Length > 8 - (Mathf.Abs(Milisecondsdigits -2)))
{
Texttodisplay = Texttodisplay.Substring(0,8- (Mathf.Abs(Milisecondsdigits -2)));
}
textdisplay.text = Texttodisplay;
}
IEnumerator TimerTake()
{
takingAway = true;
yield return new WaitForSeconds(0.01f);
secondsLeft -= 0.01;
if(secondsLeft < 10)
{
Texttodisplay = "00:0" + secondsLeft;
}
else
{
Texttodisplay = "00:" + secondsLeft;
}
takingAway = false;
}
}
请让我知道如何使它变得更准确,或者为什么它目前的行为非常不准确:/
解决方法
诸如WaitForSeconds之类的协程事件在Unity事件周期的定义点触发,该事件在处理Update()之后发生(请参见 https://docs.unity3d.com/Manual/ExecutionOrder.html)。此定义的执行点可能与计时器延迟不完全一致。这意味着它可能等待的时间比您想要的要长。
在您的示例中,您告诉它等待0.01秒。假设您以每秒30帧的速度运行游戏。每秒30帧的帧时间为1/30秒,或大约0.0333秒。然后,WaitForSeconds将等待下一帧,并经过0.0333秒,直到下一帧。然后,在下一个WaitForSeconds事件周期中,将看到延迟已经过去并触发,但是由于事件周期之间存在延迟,因此实际上您实际上等待了3倍以上。由于您的代码假定WaitForSeconds仅等待了0.01秒,因此最终等待的时间将超出您的预期。在许多应用程序中,这通常无关紧要,但是在频繁出现短暂延迟的情况下,确实可以。
要解决此问题,您有两种选择:
-
使用Update()中的Time.deltaTime手动累积时间。
协程员可能会在一帧中检查每帧的完成状态
yield WaitForSeconds
事件中也是如此。如果协程 检查是否需要继续每一帧,使用 Time.deltaTime的效率可能不会比 协程。您必须进行基准测试才能找到答案,因为协程效率更高并不是一个安全的假设。 -
使用Time.time(如果不希望缩放,则使用Time.realtimeSinceStartup)来测量WaitForSeconds触发后经过的实际时间跨度,并将其用作从剩余时间中减去的时间。
这里还需要考虑其他一些因素,如果您希望 文本显示会定期更新,您需要 动态调整您传递给WaitForSeconds的值 补偿其漂移。
您是否尝试在固定更新中不使用Corroutine来执行此操作?固定更新默认情况下每0.02秒刷新一次,但您可以在“编辑”>“设置”>“时间”>“固定时间步长”中设置为在0.01秒内运行。 用FixedUpdate中的函数替换该例程 有一个链接可以更好地说明fixedupdate的工作方式。 FixedUpdate Unity