Unity(C#)中使用Time.deltaTime仍出现倒计时变慢甚至停止问题
倒计时大数值变慢/停止问题修复
问题
作为编程新手,我在Unity里实现天/时/分/秒格式的倒计时功能,小数值下运行正常,但设置较大数值(如168800,对应约2天)时,倒计时会逐渐变慢直至停止。
原代码:
using System.Collections; using System.Collections.Generic; using UnityEngine; using TMPro; public class Timer : MonoBehaviour { [Header("Component")] public TextMeshProUGUI timerText; [Header("Timer Settings")] public float currentTime; public bool countDown; [Header("Limit Settings")] public bool hasLimit; public float timerLimit; private bool SetTimerText = false; // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { currentTime = countDown ? currentTime -= Time.DeltaTime : currentTime += Time.DeltaTime; int seconds = (int)(currentTime % 60); int minutes = (int)(currentTime / 60) % 60; int hours = (int)(currentTime / 3600) % 24; int days = (int)(currentTime / 86400); string currentTimeS = string.Format("{0:0} days {1:0} hours {2:00} minutes {3:00} seconds", days,hours,minutes,seconds); if((hasLimit) && ((countDown && currentTime <= timerLimit) || (!countDown && currentTime >= timerLimit))) { currentTime = timerLimit; SetTimerText = true; timerText.color = Color.red; enabled = false; } SetTimerText = true; if(SetTimerText){timerText.text = currentTimeS; SetTimerText = false;} } }
问题原因
核心问题是float类型的精度限制:
- float是单精度浮点数,仅支持约6-7位有效数字。当
currentTime数值很大(比如168800)时,Time.deltaTime(通常在0.016左右)相对于它来说极小,float无法精确表示两者的差值,导致每次减去Time.deltaTime时数值没有变化,最终倒计时停止。 - 代码中
SetTimerText的逻辑存在冗余,多次赋值后失去了原本的控制意义,但这不是导致倒计时停止的主因。
修复方案
把计时相关变量从float换成double(双精度浮点数,支持15-17位有效数字),足以支撑大数值下的精确计时,同时优化冗余逻辑:
修复后的代码:
using System.Collections; using System.Collections.Generic; using UnityEngine; using TMPro; public class Timer : MonoBehaviour { [Header("Component")] public TextMeshProUGUI timerText; [Header("Timer Settings")] // 改用double类型存储时间,提升精度 public double currentTime; public bool countDown; [Header("Limit Settings")] public bool hasLimit; public double timerLimit; // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { // 将Time.deltaTime转换为double参与计算,保证精度 currentTime = countDown ? currentTime -= (double)Time.deltaTime : currentTime += (double)Time.deltaTime; int seconds = (int)(currentTime % 60); int minutes = (int)(currentTime / 60) % 60; int hours = (int)(currentTime / 3600) % 24; int days = (int)(currentTime / 86400); string currentTimeS = string.Format("{0:0} days {1:0} hours {2:00} minutes {3:00} seconds", days,hours,minutes,seconds); if(hasLimit) { bool reachedLimit = countDown ? currentTime <= timerLimit : currentTime >= timerLimit; if(reachedLimit) { currentTime = timerLimit; timerText.text = currentTimeS; timerText.color = Color.red; enabled = false; return; } } // 直接更新文本,移除冗余的SetTimerText逻辑 timerText.text = currentTimeS; } }
关键修改点
- 将
currentTime和timerLimit的类型从float改为double,避免大数值下的精度损失。 - 计算时把
Time.deltaTime转换为double类型,保证计算过程的精度。 - 移除了冗余的
SetTimerText变量和逻辑,简化代码流程,直接在Update中更新文本(触发停止条件时提前返回)。
内容的提问来源于stack exchange,提问作者TensiK
相关产品推荐
相关产品推荐

