ㅇ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | using UnityEngine; using System.Collections; using System.Collections.Generic; using System; public enum CoroutinePriority { Low = 1, // 유휴 Medium = 2, // 움직임 High = 3, // 기절 Critical = 4 // 넉백 } /// <summary> /// 우선순위를 가진 코루틴을 관리하는 커스텀 코루틴 빌더. /// </summary> public class EntityCoroutineBuilder : MonoBehaviour, IEntityCoroutine { /// <summary> /// 코루틴과 그 우선순위를 저장하는 클래스. /// </summary> private class CoroutineInfo { public CoroutinePriority Priority; public IEnumerator Routine; public bool IsActive; // For handling CustomWaitForSeconds public float WaitTimeRemaining; // For handling WaitForFixedUpdate public bool WaitForFixedUpdate; public CoroutineInfo(CoroutinePriority priority, IEnumerator routine) { Priority = priority; Routine = routine; IsActive = true; WaitTimeRemaining = 0f; WaitForFixedUpdate = false; } } public class CustomWaitForSeconds { public float seconds; public CustomWaitForSeconds(float seconds) { this.seconds = seconds; } } // 활성화된 코루틴 목록 private List<CoroutineInfo> activeCoroutines = new List<CoroutineInfo>(); /// <summary> /// 우선순위를 지정하여 코루틴을 시작 /// </summary> /// <param name="priority">코루틴의 우선순위.</param> /// <param name="routine">실행할 코루틴.</param> public void StartCoroutineWithPriority(CoroutinePriority priority, IEnumerator routine) { if (!gameObject.activeInHierarchy) { Debug.LogWarning("코루틴을 시작할 수 없습니다. EntityCoroutineBuilder가 비활성화 상태"); return; } // 더 높은 우선순위의 코루틴이 시작되면 낮은 우선순위의 코루틴을 중단 List<CoroutinePriority> lowerPriorities = new List<CoroutinePriority>(); foreach (var coroutine in activeCoroutines) { if (coroutine.Priority < priority && coroutine.IsActive) { lowerPriorities.Add(coroutine.Priority); } } foreach (var lowerPriority in lowerPriorities) { Debug.Log($"Stopping coroutines with priority {lowerPriority} due to new coroutine with priority {priority}."); StopCoroutinesByPriority(lowerPriority); } // 새로운 코루틴 추가 activeCoroutines.Add(new CoroutineInfo(priority, routine)); Debug.Log($"Starting coroutine with priority {priority}."); } /// <summary> /// 특정 우선순위의 모든 코루틴을 중지 /// </summary> /// <param name="priority">중지할 코루틴의 우선순위.</param> public void StopCoroutinesByPriority(CoroutinePriority priority) { for (int i = activeCoroutines.Count - 1; i >= 0; i--) { var coroutine = activeCoroutines[i]; if (coroutine.Priority == priority && coroutine.IsActive) { coroutine.IsActive = false; activeCoroutines.RemoveAt(i); Debug.Log($"Stopped coroutine with priority {priority}."); } } } /// <summary> /// 특정 우선순위의 코루틴이 실행 중인지 확인 /// </summary> /// <param name="priority">확인할 우선순위.</param> /// <returns>해당 우선순위의 코루틴이 실행 중이면 true, 아니면 false.</returns> public bool IsCoroutineRunning(CoroutinePriority priority) { foreach (var coroutine in activeCoroutines) { if (coroutine.Priority == priority && coroutine.IsActive) return true; } return false; } private void Update() { // 코루틴 목록을 복사하여 수정 중 오류 방지 var coroutinesToProcess = new List<CoroutineInfo>(activeCoroutines); foreach (var coroutine in coroutinesToProcess) { if (!coroutine.IsActive) continue; if (coroutine.WaitForFixedUpdate) continue; // FixedUpdate에서 처리 if (coroutine.WaitTimeRemaining > 0f) { coroutine.WaitTimeRemaining -= Time.deltaTime; if (coroutine.WaitTimeRemaining > 0f) continue; } try { bool hasNext = coroutine.Routine.MoveNext(); if (!hasNext) { // 코루틴이 완료되었으면 목록에서 제거 activeCoroutines.Remove(coroutine); Debug.Log($"Coroutine Priority {coroutine.Priority} completed."); } else { HandleYieldInstruction(coroutine, coroutine.Routine.Current); } } catch (Exception ex) { Debug.LogError($"코루틴 실행 중 예외 발생 (우선순위 {coroutine.Priority}): {ex.Message}\n{ex.StackTrace}"); activeCoroutines.Remove(coroutine); } } } private void FixedUpdate() { // 코루틴 목록을 복사하여 수정 중 오류 방지 var coroutinesToProcess = new List<CoroutineInfo>(activeCoroutines); foreach (var coroutine in coroutinesToProcess) { if (!coroutine.IsActive) continue; if (!coroutine.WaitForFixedUpdate) continue; try { bool hasNext = coroutine.Routine.MoveNext(); if (!hasNext) { // 코루틴이 완료되었으면 목록에서 제거 activeCoroutines.Remove(coroutine); Debug.Log($"Coroutine Priority {coroutine.Priority} completed."); } else { HandleYieldInstruction(coroutine, coroutine.Routine.Current); } } catch (Exception ex) { Debug.LogError($"코루틴 실행 중 예외 발생 (우선순위 {coroutine.Priority}): {ex.Message}\n{ex.StackTrace}"); activeCoroutines.Remove(coroutine); } } } /// <summary> /// YieldInstruction을 처리하는 메서드. /// </summary> /// <param name="coroutine">현재 코루틴 정보.</param> /// <param name="yieldObj">현재 YieldInstruction 객체.</param> private void HandleYieldInstruction(CoroutineInfo coroutine, object yieldObj) { if (yieldObj == null) { // 단순히 다음 프레임으로 넘어감 return; } if (yieldObj is CustomWaitForSeconds customWait) { coroutine.WaitTimeRemaining = customWait.seconds; Debug.Log($"Coroutine Priority {coroutine.Priority}: Waiting for {customWait.seconds} seconds."); } else if (yieldObj is WaitForFixedUpdate) { coroutine.WaitForFixedUpdate = true; Debug.Log($"Coroutine Priority {coroutine.Priority}: Waiting for FixedUpdate."); } else { Debug.LogWarning($"지원하지 않는 YieldInstruction: {yieldObj.GetType().Name}"); } } } | cs |
C# 내장 코루틴 이용해서 만들어볼려고 이렇게 했는데
여기서 Update랑 FixedUpate() 처리를 이벤트로해서, 기본적으로 이벤트 없을때 Upate랑 FixedUpdate() 없게 해야겠지?
기본적으로 내 아키텍쳐가 이벤트 기반이라서 코루틴 동시 다발적으로 발생할 수 있어서 스택으로 우선순위 조절해서 쓰고 있는데
Unity에서 코루틴 우선순위 관련해서 만들려고하니까 기본적으로 Update가 있어야한다네
댓글 0