Unity C#中定时器结束后指定代码行未执行问题
问题原因与解决方案
核心问题
Unity中所有操作GameObject、Transform等组件的API只能在主线程调用,你用Task.Run开启了后台线程,在后台线程里修改transform的操作是非法的,要么不会执行,要么会触发线程安全异常(可查看Unity控制台确认)。
方案一:使用Unity原生协程(推荐)
这是Unity处理延迟逻辑最标准、最简单的方式:
using UnityEngine; using System.Collections; public class ClickingBehavior : MonoBehaviour { void Update() { if (Input.GetKeyDown(KeyCode.Mouse0)) { gameObject.transform.localScale += new Vector3(1, 1, 1); // 启动协程执行延迟逻辑 StartCoroutine(ScaleBackAfterDelay()); } } // 协程方法:等待2秒后缩放回原尺寸 IEnumerator ScaleBackAfterDelay() { yield return new WaitForSeconds(2f); gameObject.transform.localScale += new Vector3(-1, -1, -1); } }
方案二:基于Task的主线程调度
如果一定要用Task/async,需要把修改Transform的逻辑切回主线程执行,先实现一个主线程调度器:
using UnityEngine; using System.Collections.Generic; using System.Threading.Tasks; public class MainThreadDispatcher : MonoBehaviour { private static MainThreadDispatcher _instance; private readonly Queue<System.Action> _actions = new Queue<System.Action>(); public static MainThreadDispatcher Instance { get { if (_instance == null) { _instance = FindObjectOfType<MainThreadDispatcher>(); if (_instance == null) { var dispatcherObj = new GameObject("MainThreadDispatcher"); _instance = dispatcherObj.AddComponent<MainThreadDispatcher>(); DontDestroyOnLoad(dispatcherObj); } } return _instance; } } private void Update() { lock (_actions) { while (_actions.Count > 0) { _actions.Dequeue().Invoke(); } } } public void Enqueue(System.Action action) { lock (_actions) { _actions.Enqueue(action); } } public static async Task RunOnMainThread(System.Action action) { var tcs = new TaskCompletionSource<bool>(); Instance.Enqueue(() => { action(); tcs.SetResult(true); }); await tcs.Task; } }
再修改你的原有代码:
using UnityEngine; using System.Threading.Tasks; public class ClickingBehavior : MonoBehaviour { void Update() { if (Input.GetKeyDown(KeyCode.Mouse0)) { gameObject.transform.localScale += new Vector3(1, 1, 1); _ = ScaleBackAsync(); } } async Task ScaleBackAsync() { await Task.Delay(2000); // 切回主线程执行Transform修改 await MainThreadDispatcher.RunOnMainThread(() => { gameObject.transform.localScale += new Vector3(-1, -1, -1); }); } }
内容的提问来源于stack exchange,提问作者Mason Vogel
相关产品推荐
相关产品推荐

