You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:16:03