【Unity3D脚本与系统设计8】时间计时器
在 Unity 中实现一个 Stopwatch(计时器),通常用于测量游戏中的时间流逝,比如关卡耗时、技能冷却、UI 倒计时等。Unity 提供了 Time.time、Time.deltaTime 和 System.Diagnostics.Stopwatch 等多种方式来实现计时功能。
Time计时器
使用Unity引擎集成的Time.time,适用于游戏逻辑,如技能冷却。
using UnityEngine;
using UnityEngine.UI;public class UnityTimer : MonoBehaviour
{private float startTime;private bool isRunning = false;public Text timerText; void Update(){if (isRunning){float elapsedTime = Time.time - startTime;int minutes = Mathf.FloorToInt(elapsedTime / 60);int seconds = Mathf.FloorToInt(elapsedTime % 60);int milliseconds = Mathf.FloorToInt((elapsedTime * 1000) % 1000);timerText.text = string.Format("{0:00}:{1:00}.{2:000}", minutes, seconds, milliseconds);}}// 开始计时public void StartTimer(){startTime = Time.time;isRunning = true;}// 停止计时public void StopTimer(){isRunning = false;}
}
注意:Time.time 是从游戏启动开始的总时间(以秒为单位),受 Time.timeScale 影响(暂停时设 Time.timeScale=0 会停止增长)。
StopWatch计时器
- 使用 System.Diagnostics.Stopwatch(高精度系统级计时)
这个类来自 .NET,提供更高精度的时间测量,适合后台计时、调试、性能测试等场景或脱离 Unity 时间系统的精确计时(不受 timeScale 影响)。
using System;
using System.Diagnostics;
using UnityEngine;
using UnityEngine.UI;public class DotNetStopwatch : MonoBehaviour
{private Stopwatch stopwatch;public Text timerText;void Start(){stopwatch = new Stopwatch();}void Update(){if (stopwatch.IsRunning){long elapsedMs = stopwatch.ElapsedMilliseconds;int hours = (int)(elapsedMs / 3600000);int minutes = (int)(elapsedMs % 3600000 / 60000);int seconds = (int)(elapsedMs % 60000 / 1000);int milliseconds = (int)(elapsedMs % 1000);timerText.text = string.Format("{0:00}:{1:00}:{2:00}.{3:000}", hours, minutes, seconds, milliseconds);}}//开始计时public void StartTimer(){stopwatch.Start();}//停止计时public void StopTimer(){stopwatch.Stop();}//重置计时public void ResetTimer(){stopwatch.Reset();}//分段时间public void LapTime(){Debug.Log("Lap Time: " + stopwatch.Elapsed);}
}
进阶计时器
测试代码块的高精度计时器
源码
using System;
using System.Diagnostics;public class CustomTimer : IDisposable
{private string _timerName;private int _numTests;private Stopwatch _watch;/// <summary>/// 在构造时,启动时Stopwatch/// </summary>/// <param name="timerName">计时器名字</param>/// <param name="numTests">运行(循环)数</param>public TimeCounter(string timerName, int numTests){_timerName = timerName;_numTests = numTests;if (_numTests <= 0)_numTests = 1;_watch = Stopwatch.StartNew();}/// <summary>/// 当using块结束时自动释放/// </summary>public void Dispose(){_watch.Stop();float ms= _watch.ElapsedMilliseconds;UnityEngine.Debug.Log($"方法名:{_timerName},总耗时: {ms} 毫秒,每次循环耗时:{ms/_numTests},循环总数:{_numTests}");}
}
用法示例
int numTests= 1000000;
using (new CustomTimer ("My test", numTests))
{for (int i = 0; i < numTests; i++){//测试的代码块或方法}
}
- using块通常用于确保非托管资源超出作用域时被正确销毁。当using块结束时,它将自动调用对象的Dispose()方法来处理任何清理操作。为实现这一点,对象必须实现IDisposable接口,这迫使它定义Dispose()方法。