如何在Unity中创建无协程/Invoke的延迟SetActive自定义函数
实现带延迟的SetActive功能(非协程/Invoke方案&GameObject扩展)
一、非协程/Invoke的实现方案
如果不想依赖Unity自带的协程或Invoke,可以自己实现一个延迟任务管理器,通过单例维护任务队列,每一帧检查任务是否到期执行。这种方式完全可控,不需要依赖Unity的协程系统。
代码实现
首先创建单例管理器:
using System.Collections.Generic; using UnityEngine; public class DelayActionManager : MonoBehaviour { private static DelayActionManager _instance; private List<DelayTask> _delayTasks = new List<DelayTask>(); private struct DelayTask { public GameObject targetObj; public bool targetState; public float executeTime; } public static DelayActionManager Instance { get { if (_instance == null) { GameObject managerObj = new GameObject("DelayActionManager"); _instance = managerObj.AddComponent<DelayActionManager>(); DontDestroyOnLoad(managerObj); } return _instance; } } private void Update() { // 倒序遍历避免移除元素时索引混乱 for (int i = _delayTasks.Count - 1; i >= 0; i--) { var task = _delayTasks[i]; if (Time.time >= task.executeTime) { if (task.targetObj != null) // 避免对象已被销毁 { task.targetObj.SetActive(task.targetState); } _delayTasks.RemoveAt(i); } } } public void AddSetActiveTask(GameObject obj, bool state, float delay) { if (obj == null) return; _delayTasks.Add(new DelayTask { targetObj = obj, targetState = state, executeTime = Time.time + delay }); } }
然后实现目标函数:
public static void SetActiveWithDelay(GameObject obj, bool stateToChange, float delayTime) { DelayActionManager.Instance.AddSetActiveTask(obj, stateToChange, delayTime); }
调用方式完全符合你的需求:
SetActiveWithDelay(GameObjectToPass, true, 2f);
二、协程/Invoke是否为更优方案?
其实协程是更推荐的方案,原因如下:
- 协程是Unity原生支持的轻量级异步方案,底层由Unity管理,性能开销极低,远低于自己维护队列的开销(尤其是任务量小时)。
- 代码更简洁,不需要额外维护管理器类,直接在MonoBehaviour中写协程即可:
public static IEnumerator SetActiveWithDelayCoroutine(GameObject obj, bool state, float delay) { yield return new WaitForSeconds(delay); if (obj != null) obj.SetActive(state); } // 调用时: StartCoroutine(SetActiveWithDelayCoroutine(GameObjectToPass, true, 2f)); - Invoke本质是反射调用,性能略差于协程,且灵活性低(无法传递复杂参数、中途取消麻烦),一般只用于简单的延迟调用。
如果你的顾虑是“和直接用协程没区别”——其实这正是协程的优势:它就是专门解决这类帧延迟/时间延迟问题的,没必要为了“不用协程”而额外造轮子,除非你有大量统一管理延迟任务的需求。
三、扩展GameObject类实现直接调用
用C#的扩展方法就能实现GameObject.SetActiveWithDelay(true,2f)的调用方式,代码非常简单:
using UnityEngine; public static class GameObjectExtensions { public static void SetActiveWithDelay(this GameObject obj, bool state, float delay) { // 这里可以选择用协程或者上面的管理器方案,比如用协程的话: if (obj == null) return; obj.StartCoroutine(SetActiveCoroutine(obj, state, delay)); } private static IEnumerator SetActiveCoroutine(GameObject obj, bool state, float delay) { yield return new WaitForSeconds(delay); if (obj != null) obj.SetActive(state); } }
现在你可以直接在任何GameObject对象上调用:
GameObjectToPass.SetActiveWithDelay(true, 2f);
如果不想用协程,也可以把扩展方法里的逻辑换成调用DelayActionManager的方法。
内容的提问来源于stack exchange,提问作者IcyThug
相关产品推荐
相关产品推荐

