Unity中该FPS计数器实现方案是否符合精准平滑的需求?
关于FPS统计代码的有效性疑问
我编写了一段用于计算平均FPS的代码,设置每0.4秒更新FPS文本显示,每2秒重置平均FPS统计。我需要实现精准且平滑的FPS统计(消除临时帧率波动),请问这段代码是否能满足我的需求?
[RequireComponent(typeof(TMP_Text))] public class FpsCounter : MonoBehaviour { private struct AverageFloat { public float Average => _value / _count; private float _value; private int _count; public void Add(float number) { _value += number; _count++; } public void Reset() { _value = 0f; _count = 0; } } [SerializeField] private float _averageValueCollectionTime = 2f; [SerializeField] private float _refreshFrequency = 0.4f; private float _timeSinceFpsReset = 0f; private float _timeSinceUpdate = 0f; private AverageFloat _fpsValue; private TMP_Text _text; private void Start() { _text = GetComponent<TMP_Text>(); } private void Update() { if (_timeSinceFpsReset > _averageValueCollectionTime) { _timeSinceFpsReset = 0; _fpsValue.Reset(); } _fpsValue.Add(1f / Time.unscaledDeltaTime); _timeSinceFpsReset += Time.deltaTime; if (_timeSinceUpdate < _refreshFrequency) { _timeSinceUpdate += Time.deltaTime; return; } int fps = Mathf.RoundToInt(_fpsValue.Average); _text.text = fps.ToString(); _timeSinceUpdate = 0f; } }
代码分析与结论
这段代码基本能满足平滑FPS统计的需求,但在精准性上有几个细节可以优化:
- 平滑性达标:通过2秒窗口内的FPS平均值过滤临时波动,每0.4秒更新一次显示,不会出现频繁跳变,符合平滑要求。
- 精准性的潜在问题:
- 计时与统计基准不一致:统计FPS用
Time.unscaledDeltaTime(不受游戏时间缩放影响),但计时用Time.deltaTime,如果游戏开启慢动作或暂停,重置和更新时机就会出错。 - 统计窗口错位:当前用
_timeSinceFpsReset > _averageValueCollectionTime触发重置,会导致实际统计窗口略长于设定的2秒,比如可能到2.1秒才重置,统计的是过去2.1秒的FPS。 - 除以0风险:
AverageFloat的Average属性在_count为0时会触发除以0错误,虽然实际运行中概率极低,但仍需规避。
- 计时与统计基准不一致:统计FPS用
优化后的代码
[RequireComponent(typeof(TMP_Text))] public class FpsCounter : MonoBehaviour { private struct AverageFloat { // 增加_count为0的判断,避免除以0 public float Average => _count == 0 ? 0f : _value / _count; private float _value; private int _count; public void Add(float number) { _value += number; _count++; } public void Reset() { _value = 0f; _count = 0; } } [SerializeField] private float _averageValueCollectionTime = 2f; [SerializeField] private float _refreshFrequency = 0.4f; private float _timeSinceFpsReset = 0f; private float _timeSinceUpdate = 0f; private AverageFloat _fpsValue; private TMP_Text _text; private void Start() { _text = GetComponent<TMP_Text>(); } private void Update() { float unscaledDelta = Time.unscaledDeltaTime; // 统一用unscaledDeltaTime计时,避免时间缩放影响 _timeSinceFpsReset += unscaledDelta; // 用>=判断,并且保留超出的时间,让统计窗口精准对齐 if (_timeSinceFpsReset >= _averageValueCollectionTime) { _timeSinceFpsReset -= _averageValueCollectionTime; _fpsValue.Reset(); } _fpsValue.Add(1f / unscaledDelta); _timeSinceUpdate += unscaledDelta; if (_timeSinceUpdate < _refreshFrequency) { return; } int fps = Mathf.RoundToInt(_fpsValue.Average); _text.text = fps.ToString(); _timeSinceUpdate = 0f; } }
优化后的代码解决了上述问题,能精准控制统计周期,不受游戏时间缩放影响,同时保留了原有的平滑效果,完全满足你对精准且平滑FPS统计的需求。
内容的提问来源于stack exchange,提问作者purepelmen
相关产品推荐
相关产品推荐

