北京公司建设网站手机软件商城免费下载
2026/4/18 20:46:01 网站建设 项目流程
北京公司建设网站,手机软件商城免费下载,浏览器网站进入口,团购网站模板免费下载Unity 中的 IEnumerator 是 C# 迭代器接口#xff0c;主要用于实现 协程#xff08;Coroutines#xff09;#xff0c;这是 Unity 中处理异步操作和时间控制的核心机制。基本概念1. 什么是协程#xff1f;协程是一种特殊的函数#xff0c;可以在执行过程中暂停#xff0…Unity 中的IEnumerator是 C# 迭代器接口主要用于实现协程Coroutines这是 Unity 中处理异步操作和时间控制的核心机制。基本概念1.什么是协程协程是一种特殊的函数可以在执行过程中暂停并在稍后恢复执行而不是一次性执行完毕。2.基本语法csharpusing System.Collections; using UnityEngine; public class CoroutineExample : MonoBehaviour { void Start() { // 启动协程 StartCoroutine(MyCoroutine()); } IEnumerator MyCoroutine() { Debug.Log(协程开始); // 暂停1秒 yield return new WaitForSeconds(1f); Debug.Log(1秒后); // 暂停到下一帧 yield return null; Debug.Log(下一帧); } }常用 yield 指令时间控制csharpIEnumerator TimeControls() { // 等待1秒 yield return new WaitForSeconds(1f); // 等待固定物理更新帧 yield return new WaitForFixedUpdate(); // 等待帧结束 yield return new WaitForEndOfFrame(); // 等待真实时间不受Time.timeScale影响 yield return new WaitForSecondsRealtime(1f); }条件等待csharpIEnumerator WaitForConditions() { // 等待直到条件为真 yield return new WaitUntil(() Input.GetKeyDown(KeyCode.Space)); // 等待当条件为真时 yield return new WaitWhile(() Input.GetKey(KeyCode.Space)); // 等待异步操作完成 AsyncOperation asyncOp SceneManager.LoadSceneAsync(SceneName); yield return asyncOp; }实际应用示例1. 延迟执行csharpIEnumerator DelayedAction(float delay, System.Action action) { yield return new WaitForSeconds(delay); action?.Invoke(); } // 使用 StartCoroutine(DelayedAction(2f, () { Debug.Log(2秒后执行); }));2. 序列动画csharpIEnumerator SequenceAnimation() { transform.position startPos; yield return new WaitForSeconds(0.5f); // 移动到目标位置耗时1秒 float elapsed 0f; while (elapsed 1f) { transform.position Vector3.Lerp(startPos, targetPos, elapsed); elapsed Time.deltaTime; yield return null; // 每帧执行 } transform.position targetPos; }3. 分帧处理大数据csharpIEnumerator ProcessLargeData(ListGameObject objects) { for (int i 0; i objects.Count; i) { // 处理每个对象 ProcessObject(objects[i]); // 每处理10个对象等待一帧避免卡顿 if (i % 10 0) yield return null; } }4. 网络请求csharpIEnumerator LoadDataFromServer(string url) { UnityWebRequest request UnityWebRequest.Get(url); yield return request.SendWebRequest(); if (request.result UnityWebRequest.Result.Success) { Debug.Log(数据加载成功: request.downloadHandler.text); } else { Debug.LogError(加载失败: request.error); } }协程控制方法csharppublic class CoroutineControl : MonoBehaviour { private Coroutine myCoroutine; void Start() { // 启动协程并保存引用 myCoroutine StartCoroutine(RunningCoroutine()); // 带参数的协程 StartCoroutine(ParameterCoroutine(参数, 123)); } void StopMyCoroutine() { if (myCoroutine ! null) { // 停止特定协程 StopCoroutine(myCoroutine); // 或停止所有协程 // StopAllCoroutines(); } } IEnumerator RunningCoroutine() { while (true) { Debug.Log(运行中...); yield return new WaitForSeconds(1f); } } IEnumerator ParameterCoroutine(string text, int number) { Debug.Log($参数: {text}, {number}); yield return null; } }嵌套协程csharpIEnumerator MainCoroutine() { Debug.Log(主协程开始); // 等待子协程完成 yield return StartCoroutine(SubCoroutine()); Debug.Log(子协程完成); } IEnumerator SubCoroutine() { yield return new WaitForSeconds(2f); Debug.Log(子协程执行); }注意事项1. 性能考虑csharp// 避免每帧创建新的 WaitForSeconds IEnumerator BadPerformance() { while (true) { yield return new WaitForSeconds(1f); // 每循环都创建新对象 } } // 推荐缓存 WaitForSeconds IEnumerator BetterPerformance() { WaitForSeconds wait new WaitForSeconds(1f); while (true) { yield return wait; // 复用对象 } }2. 协程生命周期协程在 GameObject 被禁用时不会自动停止协程在 GameObject 被销毁时会自动停止协程在场景切换时会被销毁3. 错误处理csharpIEnumerator SafeCoroutine() { try { yield return StartCoroutine(RiskyOperation()); } catch (System.Exception e) { Debug.LogError($协程错误: {e.Message}); } }高级用法自定义 YieldInstructioncsharppublic class WaitForCustomCondition : CustomYieldInstruction { private System.Funcbool predicate; public override bool keepWaiting !predicate(); public WaitForCustomCondition(System.Funcbool predicate) { this.predicate predicate; } } // 使用 yield return new WaitForCustomCondition(() player.IsReady);协程管理器csharppublic static class CoroutineManager { public static Coroutine Start(IEnumerator coroutine) { GameObject obj new GameObject(CoroutineRunner); MonoBehaviour runner obj.AddComponentMonoBehaviourRunner(); Coroutine routine runner.StartCoroutine(coroutine); // 协程完成后自动销毁 runner.StartCoroutine(Cleanup(routine, obj)); return routine; } static IEnumerator Cleanup(Coroutine coroutine, GameObject obj) { yield return coroutine; GameObject.Destroy(obj); } class MonoBehaviourRunner : MonoBehaviour { } }常见问题解决协程不执行检查是否调用了StartCoroutine()确保 MonoBehaviour 脚本已启用检查 yield 指令是否正确协程内存泄漏csharpvoid OnDestroy() { // 在对象销毁时停止所有协程 StopAllCoroutines(); }协程是 Unity 中非常强大的工具合理使用可以简化很多异步操作的实现让代码更加清晰易读。补充与优化一、性能优化策略1.缓存 Yield 指令关键优化csharppublic class OptimizedCoroutines : MonoBehaviour { // ❌ 坏做法每次循环都创建新对象 IEnumerator BadWay() { while (true) { yield return new WaitForSeconds(1f); // GC 分配 } } // ✅ 好做法缓存重用 IEnumerator GoodWay() { var waitOneSecond new WaitForSeconds(1f); var waitEndOfFrame new WaitForEndOfFrame(); var waitFixedUpdate new WaitForFixedUpdate(); while (true) { yield return waitOneSecond; // 无GC分配 } } // 高级优化预定义常用时间间隔 private static readonly Dictionaryfloat, WaitForSeconds _waitCache new Dictionaryfloat, WaitForSeconds(); public static WaitForSeconds GetWait(float seconds) { if (!_waitCache.TryGetValue(seconds, out var wait)) { wait new WaitForSeconds(seconds); _waitCache[seconds] wait; } return wait; } IEnumerator OptimizedWay() { yield return GetWait(0.5f); yield return GetWait(1f); yield return GetWait(0.5f); // 复用缓存 } }2.避免每帧的协程开销csharppublic class UpdateVsCoroutine : MonoBehaviour { // ❌ 协程每帧的开销 Update IEnumerator CoroutineUpdate() { while (true) { // 每帧执行的逻辑 transform.Rotate(Vector3.up * Time.deltaTime * 90); yield return null; // 分配开销 } } // ✅ 对于简单每帧逻辑使用 Update 更高效 void Update() { transform.Rotate(Vector3.up * Time.deltaTime * 90); } // 最佳实践协程适合不连续的时间操作 IEnumerator ProperUse() { // 延迟执行 yield return GetWait(2f); // 一段时间内的动画 yield return MoveToPosition(Vector3.zero, 1f); // 等待条件 yield return new WaitUntil(() Input.GetKeyDown(KeyCode.Space)); } }3.批量处理与分帧csharppublic class BatchProcessing : MonoBehaviour { // 优化大数据处理 IEnumerator ProcessLargeBatchT(ListT items, System.ActionT process, int batchSize 10) { int processed 0; for (int i 0; i items.Count; i) { process(items[i]); processed; // 每处理 batchSize 个等待一帧 if (processed batchSize) { processed 0; yield return null; // 让出一帧避免卡顿 } } } // 智能自适应批处理 IEnumerator AdaptiveBatchProcessT(ListT items, System.ActionT process) { int batchSize 10; float targetFrameTime 1f / 60f; // 60FPS for (int i 0; i items.Count; i batchSize) { float startTime Time.realtimeSinceStartup; // 处理一批 int end Mathf.Min(i batchSize, items.Count); for (int j i; j end; j) { process(items[j]); } // 自适应调整批大小 float elapsed Time.realtimeSinceStartup - startTime; if (elapsed targetFrameTime * 0.5f) { batchSize Mathf.Min(batchSize * 2, 100); // 加倍最多100 } else if (elapsed targetFrameTime) { batchSize Mathf.Max(batchSize / 2, 1); // 减半最少1 } yield return null; } } }二、高级协程模式1.协程状态机模式csharppublic class CoroutineStateMachine : MonoBehaviour { public enum State { Idle, Moving, Attacking, Dead } private State currentState; private Coroutine currentRoutine; void ChangeState(State newState) { if (currentRoutine ! null) StopCoroutine(currentRoutine); currentState newState; switch (newState) { case State.Idle: currentRoutine StartCoroutine(IdleState()); break; case State.Moving: currentRoutine StartCoroutine(MovingState()); break; case State.Attacking: currentRoutine StartCoroutine(AttackingState()); break; } } IEnumerator IdleState() { Debug.Log(进入空闲状态); var wait new WaitForSeconds(Random.Range(1f, 3f)); while (currentState State.Idle) { yield return wait; // 随机切换到移动状态 if (Random.value 0.5f) { ChangeState(State.Moving); yield break; } } } IEnumerator MovingState() { /* ... */ } IEnumerator AttackingState() { /* ... */ } }2.链式协程Promise风格csharppublic class CoroutineChain { public static IEnumerator Sequence(params IEnumerator[] routines) { foreach (var routine in routines) { yield return routine; } } public static IEnumerator Parallel(MonoBehaviour runner, params IEnumerator[] routines) { ListCoroutine coroutines new ListCoroutine(); foreach (var routine in routines) { coroutines.Add(runner.StartCoroutine(routine)); } // 等待所有协程完成 foreach (var coroutine in coroutines) { yield return coroutine; } } // 使用示例 IEnumerator ComplexAnimation() { yield return Sequence( MoveTo(new Vector3(0, 0, 0), 1f), Parallel( Rotate(360f, 1f), ScaleTo(Vector3.one * 2, 1f) ), WaitForSeconds(0.5f), FadeOut(1f) ); } IEnumerator MoveTo(Vector3 target, float duration) { /* ... */ } IEnumerator Rotate(float angle, float duration) { /* ... */ } IEnumerator ScaleTo(Vector3 scale, float duration) { /* ... */ } IEnumerator FadeOut(float duration) { /* ... */ } }3.带取消功能的协程csharppublic class CancellableCoroutine { public class CancellationToken { public bool IsCancelled { get; private set; } public event System.Action OnCancel; public void Cancel() { if (!IsCancelled) { IsCancelled true; OnCancel?.Invoke(); } } } public static IEnumerator WithCancellation(IEnumerator routine, CancellationToken token) { while (routine.MoveNext()) { if (token.IsCancelled) yield break; yield return routine.Current; } } // 使用示例 IEnumerator DownloadWithTimeout(string url, float timeout) { var cancellation new CancellationToken(); // 设置超时 StartCoroutine(TimeoutCoroutine(timeout, cancellation)); // 执行下载 yield return WithCancellation(DownloadFile(url), cancellation); } IEnumerator TimeoutCoroutine(float delay, CancellationToken token) { yield return new WaitForSeconds(delay); token.Cancel(); Debug.Log(操作超时); } }三、协程管理器系统1.统一协程管理csharppublic class CoroutineManager : MonoBehaviour { private static CoroutineManager _instance; private Dictionarystring, Coroutine _runningCoroutines new Dictionarystring, Coroutine(); public static CoroutineManager Instance { get { if (_instance null) { GameObject obj new GameObject(CoroutineManager); _instance obj.AddComponentCoroutineManager(); DontDestroyOnLoad(obj); } return _instance; } } // 启动并跟踪协程 public Coroutine StartTrackedCoroutine(IEnumerator routine, string id null) { if (string.IsNullOrEmpty(id)) id Guid.NewGuid().ToString(); var coroutine StartCoroutine(TrackedRoutine(routine, id)); _runningCoroutines[id] coroutine; return coroutine; } private IEnumerator TrackedRoutine(IEnumerator routine, string id) { yield return routine; _runningCoroutines.Remove(id); } // 按ID停止协程 public bool StopTrackedCoroutine(string id) { if (_runningCoroutines.TryGetValue(id, out var coroutine)) { StopCoroutine(coroutine); _runningCoroutines.Remove(id); return true; } return false; } // 暂停/恢复所有协程 public void PauseAllCoroutines() { foreach (var kvp in _runningCoroutines) { // 暂停逻辑 - 需要自定义实现 // 可以使用 Time.timeScale 0但会影响所有协程 } } // 获取运行中协程信息 public Dictionarystring, System.Type GetRunningCoroutinesInfo() { // 返回协程类型信息便于调试 return new Dictionarystring, System.Type(); } }2.优先级调度系统csharppublic class PriorityCoroutineScheduler : MonoBehaviour { public enum Priority { Low, Normal, High, Critical } private class CoroutineTask { public IEnumerator Routine; public Priority Priority; public float StartTime; public Coroutine Coroutine; } private ListCoroutineTask _pendingTasks new ListCoroutineTask(); private ListCoroutineTask _runningTasks new ListCoroutineTask(); private int _maxConcurrent 3; // 最大同时运行数 public void Schedule(IEnumerator routine, Priority priority Priority.Normal) { var task new CoroutineTask { Routine routine, Priority priority, StartTime Time.time }; _pendingTasks.Add(task); _pendingTasks.Sort((a, b) a.Priority.CompareTo(b.Priority) * -1); // 降序 TryStartNext(); } private void TryStartNext() { while (_runningTasks.Count _maxConcurrent _pendingTasks.Count 0) { var task _pendingTasks[0]; _pendingTasks.RemoveAt(0); task.Coroutine StartCoroutine(RunTask(task)); _runningTasks.Add(task); } } private IEnumerator RunTask(CoroutineTask task) { yield return task.Routine; _runningTasks.Remove(task); TryStartNext(); } }四、调试与监控1.协程性能监控csharppublic class CoroutineProfiler : MonoBehaviour { private class CoroutineInfo { public string Name; public float StartTime; public float TotalTime; public int FrameCount; public StackTrace CreationStackTrace; } private DictionaryCoroutine, CoroutineInfo _activeCoroutines new DictionaryCoroutine, CoroutineInfo(); public Coroutine StartProfiledCoroutine(IEnumerator routine, string name null) { if (name null) name routine.ToString(); var coroutine StartCoroutine(ProfiledRoutine(routine, name)); _activeCoroutines[coroutine] new CoroutineInfo { Name name, StartTime Time.realtimeSinceStartup, CreationStackTrace new System.Diagnostics.StackTrace(true) }; return coroutine; } private IEnumerator ProfiledRoutine(IEnumerator innerRoutine, string name) { var startTime Time.realtimeSinceStartup; int frameCount 0; while (innerRoutine.MoveNext()) { frameCount; yield return innerRoutine.Current; } float duration Time.realtimeSinceStartup - startTime; Debug.Log($协程 {name} 完成: {duration:F2}s, {frameCount}帧); } void OnGUI() { if (!Application.isEditor) return; GUILayout.BeginArea(new Rect(10, 10, 400, 300)); GUILayout.Label(运行中协程:); foreach (var kvp in _activeCoroutines) { float duration Time.realtimeSinceStartup - kvp.Value.StartTime; GUILayout.Label(${kvp.Value.Name}: {duration:F2}s); } GUILayout.EndArea(); } }2.协程异常处理csharppublic class SafeCoroutineRunner : MonoBehaviour { public static IEnumerator WithErrorHandling(IEnumerator routine, System.ActionSystem.Exception onError null) { while (true) { object current; try { if (!routine.MoveNext()) yield break; current routine.Current; } catch (System.Exception e) { onError?.Invoke(e); Debug.LogError($协程错误: {e.Message}\n{e.StackTrace}); yield break; } yield return current; } } // 重试机制 public static IEnumerator WithRetry(IEnumerator routine, int maxRetries 3) { int attempts 0; while (attempts maxRetries) { try { yield return routine; break; // 成功完成 } catch (System.Exception e) { attempts; Debug.LogWarning($第{attempts}次尝试失败: {e.Message}); if (attempts maxRetries) { Debug.LogError($达到最大重试次数); throw; } yield return new WaitForSeconds(Mathf.Pow(2, attempts)); // 指数退避 } } } }五、Unity 2021 新特性1.UniTask 替代方案第三方库csharp// UniTask 比协程更高效支持 async/await using Cysharp.Threading.Tasks; public class UniTaskExample : MonoBehaviour { async UniTaskVoid Start() { // 并行执行多个异步任务 await UniTask.WhenAll( LoadAssetAsync(Prefabs/Character), LoadSceneAsync(Level1), WaitForSecondsAsync(1f) ); // 取消支持 var cancellationToken this.GetCancellationTokenOnDestroy(); await MoveToPositionAsync(Vector3.zero, 1f, cancellationToken); } async UniTask LoadAssetAsync(string path) { // 异步加载资源 await Resources.LoadAsyncGameObject(path); } async UniTask WaitForSecondsAsync(float seconds) { await UniTask.Delay((int)(seconds * 1000)); } }2.C# 8.0 Async Streamscsharp// Unity 2021.2 支持 C# 8.0 public async System.Collections.Generic.IAsyncEnumerableint GenerateSequence() { for (int i 0; i 20; i) { await UniTask.Delay(100); // 模拟异步操作 yield return i; } } async UniTaskVoid ConsumeAsyncStream() { await foreach (var number in GenerateSequence()) { Debug.Log(number); } }六、最佳实践总结DOs推荐做✅缓存常用 Wait 对象减少GC✅使用协程处理异步/时间相关逻辑✅为长时间协程添加取消支持✅使用协程管理器统一管理✅添加错误处理防止崩溃传播✅分帧处理大数据避免卡顿DONTs避免做❌避免每帧都用协程简单逻辑用Update❌不要创建大量短期协程复用已有的❌避免在协程中直接修改已销毁对象❌不要依赖协程精确时序Unity不是实时系统❌避免多层嵌套协程难以维护和调试进阶建议考虑使用 UniTask替代协程获得更好性能实现协程优先级调度优化资源使用添加协程监控便于调试和性能分析使用状态机模式管理复杂协程逻辑这些优化策略和高级模式可以帮助你构建更健壮、高性能的Unity应用。根据项目规模和需求选择合适的方案。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询