Unity非Update函数内无限循环导致程序挂起问题求助
嘿,我一眼就看穿问题所在啦!你的Timer类里的GenerateTicks()方法用了一个阻塞式的while循环,这在Unity的主线程环境下直接导致了程序挂起——原因很简单:
Unity的核心运行逻辑(包括更新Time.time、渲染画面、处理用户输入、执行其他脚本逻辑)都在同一个主线程里执行。当你调用StartTimer()后,GenerateTicks()立刻进入了while(timerRunning)循环,这个循环会完全霸占主线程,根本不给Unity任何机会去更新Time.time的值,也没法处理其他任何任务。
结果就是:Time.time会永远停留在进入循环的那一刻,(Time.time - lastTicktime)永远不会超过tickTime,循环就会无限跑下去,程序自然就挂死了。
两种可行的解决方案
方案1:使用Unity协程(推荐)
协程是Unity处理定时/异步任务的标准方式,它能在执行过程中主动让出主线程,不会造成阻塞。修改你的Timer类如下:
using System.Collections; using UnityEngine; public class Timer : MonoBehaviour { float tickTime; bool timerRunning = false; public Timer(float tickTime) { this.tickTime = tickTime; } public void StartTimer() { timerRunning = true; StartCoroutine(GenerateTicksCoroutine()); } public void StopTimer() { timerRunning = false; } IEnumerator GenerateTicksCoroutine() { while (timerRunning) { Debug.Log("Tick"); // 让出主线程,等待指定时间后再继续执行 yield return new WaitForSeconds(tickTime); } } }
然后在实现脚本里,需要确保Timer组件挂载在一个GameObject上(Unity的协程必须依附于MonoBehaviour):
Timer timer; public float triggerTime = 1f; // 你可以在Inspector里设置这个值 void Start() { // 动态创建一个GameObject来挂载Timer组件 GameObject timerHolder = new GameObject("TimerHolder"); timer = timerHolder.AddComponent<Timer>(); timer.StartTimer(); }
方案2:使用Update方法
如果你的定时任务不需要特别精确的间隔,也可以用Update方法来轮询检查时间:
using UnityEngine; public class Timer : MonoBehaviour { float tickTime; float lastTickTime; bool timerRunning = false; public Timer(float tickTime) { this.tickTime = tickTime; } public void StartTimer() { timerRunning = true; lastTickTime = Time.time; } public void StopTimer() { timerRunning = false; } void Update() { if (timerRunning && (Time.time - lastTickTime) > tickTime) { Debug.Log("Tick"); lastTickTime = Time.time; } } }
实现方式和协程版本一致,需要将Timer挂载到GameObject上。
补充说明
你提到之前这么写能运行,大概率是记错了场景——要么是之前的代码用了协程/Update而不是阻塞循环,要么是尝试在子线程中运行?但要注意:Unity的大部分API(比如Debug.Log、Time.time)都不能在子线程中调用,会引发错误,所以协程或Update才是最稳妥的选择。
内容的提问来源于stack exchange,提问作者Don

