using System.Collections;
using System.Collections.Generic;
public class TimeManager : MonoBehaviour
// 使用字典保存 Coroutine 和其执行器,以便快速查找和管理
private static Dictionary<Coroutine, CoroutineExecutor> coroutineExecutors =
new Dictionary<Coroutine, CoroutineExecutor>();
// 辅助类,用于执行 Coroutine 并管理其状态
private class CoroutineExecutor : MonoBehaviour
public bool IsPaused { get; private set; } = false;
/// <param name="delay">延迟秒数。</param>
/// <param name="onComplete">延迟后执行的 Action。</param>
/// <returns>返回 Coroutine 引用,可用于手动停止、暂停和恢复。</returns>
public static Coroutine Delay(float delay, Action onComplete)
Debug.LogError("延迟时间不能为负数!");
GameObject executorObject = new GameObject("TimeManagerExecutor");
DontDestroyOnLoad(executorObject);
CoroutineExecutor executor = executorObject.AddComponent<CoroutineExecutor>();
IEnumerator coroutineRoutine = DelayCoroutine(delay, onComplete, executorObject, executor);
Coroutine coroutine = executor.StartCoroutine(coroutineRoutine);
coroutineExecutors.Add(coroutine, executor);
private static IEnumerator DelayCoroutine(
GameObject executorObject,
CoroutineExecutor executor
float startTime = Time.time;
while (Time.time < startTime + delay)
while (executor.IsPaused)
/// 每隔一段时间重复执行一个 Action,直到达到指定时长或次数。
/// <param name="interval">重复的间隔秒数。</param>
/// <param name="duration">持续的总时长(可选)。</param>
/// <param name="count">重复的次数(可选)。</param>
/// <param name="onRepeat">每次重复执行的 Action。</param>
/// <returns>返回 Coroutine 引用,可用于手动停止、暂停和恢复。</returns>
public static Coroutine Repeat(
Debug.LogError("重复间隔必须大于0!");
GameObject executorObject = new GameObject("TimeManagerExecutor");
DontDestroyOnLoad(executorObject);
CoroutineExecutor executor = executorObject.AddComponent<CoroutineExecutor>();
IEnumerator coroutineRoutine = RepeatCoroutine(
Coroutine coroutine = executor.StartCoroutine(coroutineRoutine);
coroutineExecutors.Add(coroutine, executor);
private static IEnumerator RepeatCoroutine(
GameObject executorObject,
CoroutineExecutor executor
while (executor.IsPaused)
if ((duration > 0 && timer >= duration) || (count > 0 && currentCount >= count))
yield return new WaitForSeconds(interval);
/// 等待某个条件为真时,再执行一个 Action。
/// <param name="predicate">等待的条件,返回 true 时继续执行。</param>
/// <param name="onComplete">条件满足时执行的 Action。</param>
/// <returns>返回 Coroutine 引用,可用于手动停止、暂停和恢复。</returns>
public static Coroutine WaitUntil(Func<bool> predicate, Action onComplete)
return WaitUntil(predicate, -1f, onComplete, null);
/// <param name="predicate">等待的条件,返回 true 时继续执行。</param>
/// <param name="timeout">超时时间(秒)。</param>
/// <param name="onComplete">条件满足时执行的 Action。</param>
/// <param name="onTimeout">超时时执行的 Action。</param>
/// <returns>返回 Coroutine 引用,可用于手动停止、暂停和恢复。</returns>
public static Coroutine WaitUntil(
Debug.LogError("等待条件不能为空!");
GameObject executorObject = new GameObject("TimeManagerExecutor");
DontDestroyOnLoad(executorObject);
CoroutineExecutor executor = executorObject.AddComponent<CoroutineExecutor>();
IEnumerator coroutineRoutine = WaitUntilCoroutine(
Coroutine coroutine = executor.StartCoroutine(coroutineRoutine);
coroutineExecutors.Add(coroutine, executor);
private static IEnumerator WaitUntilCoroutine(
GameObject executorObject,
CoroutineExecutor executor
float startTime = Time.time;
bool conditionMet = false;
while (!conditionMet && (timeout < 0 || Time.time - startTime < timeout))
while (executor.IsPaused)
/// 手动停止一个由 TimeManager 启动的 Coroutine。
public static void Stop(Coroutine coroutine)
if (coroutineExecutors.TryGetValue(coroutine, out CoroutineExecutor executor))
executor.StopCoroutine(coroutine);
Cleanup(executor.gameObject);
/// 暂停一个由 TimeManager 启动的 Coroutine。
public static void Pause(Coroutine coroutine)
if (coroutineExecutors.TryGetValue(coroutine, out CoroutineExecutor executor))
/// 恢复一个由 TimeManager 启动的 Coroutine。
public static void Resume(Coroutine coroutine)
if (coroutineExecutors.TryGetValue(coroutine, out CoroutineExecutor executor))
/// 停止所有由 TimeManager 启动的 Coroutine。
public static void StopAll()
foreach (var executor in coroutineExecutors.Values)
if (executor != null && executor.gameObject != null)
executor.StopAllCoroutines();
Destroy(executor.gameObject);
coroutineExecutors.Clear();
private static void Cleanup(GameObject executorObject)
if (executorObject != null)
CoroutineExecutor executor = executorObject.GetComponent<CoroutineExecutor>();
List<Coroutine> keysToRemove = new List<Coroutine>();
foreach (var entry in coroutineExecutors)
if (entry.Value == executor)
keysToRemove.Add(entry.Key);
foreach (var key in keysToRemove)
coroutineExecutors.Remove(key);
// myRepeatedTask = TimeManager.Repeat(1f, () => {
// Debug.Log("我在重复执行...");
// TimeManager.WaitUntil(
// Debug.Log("<b><color=green>示例1:条件已满足,任务完成!</color></b>");
// Debug.Log("<b><color=red>示例1:任务超时!</color></b>");