Coroutine
Coroutine은 yield return으로 멈추었다가 나중에 재개하는 특수 메서드로 메인 스레드를 막지 않습니다. WaitForSeconds 캐시·StopCoroutine·WaitUntil·코루틴 체이닝으로 다프레임 로직을 다룹니다. 핵심 개념과 실습을 함께 익힙니다.
상상해 보세요...
Coroutine은 책의 책갈피와 같습니다. 읽다(코드 실행)가 대기를 만나면 책갈피(yield return)를 꽂고 책을 닫아 다른 일을 합니다. 다음 프레임에 Unity가 책갈피에서 이어 읽습니다. async/await와 달리 코루틴은 메인 스레드에 머물러 Unity 라이프사이클과 완전히 연결됩니다.
개념 자세히
Coroutine은 IEnumerator——C# 이터레이터 프로토콜입니다. 각
yield return은 yield instruction을
내놓습니다: null(1프레임 대기), WaitForSeconds(t),
WaitForFixedUpdate(), WaitUntil(predicate)…
StartCoroutine vs async: 코루틴은 Unity 메인
스레드에서 돌며 모든 Unity API에 접근할 수 있습니다. async/await는
(SynchronizationContext를 유지하지 않으면) 다른 스레드에서 재개될 수 있습니다.
MonoBehaviour가 비활성/파괴되면 코루틴은 멈추고, async는 스스로 멈추지 않습니다.
WaitForSeconds 캐시:
new WaitForSeconds(t)는 호출마다 할당됩니다. 저장해 재사용하세요:
var wait = new WaitForSeconds(2f);를 루프 안에서.
중지: StopCoroutine()에는
StartCoroutine이 반환한 Coroutine 핸들이 필요합니다.
StopAllCoroutines()는 그 MonoBehaviour의 모든 코루틴을 멈춥니다.
다이어그램: Coroutine vs Update
❌ Update approach (polling)
void Update() {
if (Time.time > startTime + 2f)
DoAction(); // 매 프레임 검사!
}
⚡ 필요 없어도 매 프레임 조건 검사
✅ Coroutine approach
IEnumerator Delayed() {
yield return new WaitForSeconds(2f);
DoAction(); // 한 번만 실행
}
✅ 대기 중 CPU 비용 없음
여러 프레임에 걸친 Coroutine 타임라인:
실습 단계
IEnumerator 정의
IEnumerator를 반환하고 yield return이 하나 이상인 메서드.
StartCoroutine으로 시작
Coroutine co = StartCoroutine(MyCoroutine()) — 나중에 멈추려면 핸들을 보관.
WaitForSeconds 캐시
클래스 상단에서 한 번 만들고 루프에서 재사용: _waitSec = new WaitForSeconds(0.5f).
필요할 때 중지
StopCoroutine(co) 또는 OnDisable에서 StopAllCoroutines().
인터랙티브 시뮬레이터
Coroutine 타입을 고르고 Start를 눌러 프레임을 가로질러 진행하는 모습을 보세요.
Code Execution
Frame Timeline
StartCoroutine을 누르세요...
코드 예제
기본기본 FadeOut 효과와 지연 액션.
using System.Collections;
using UnityEngine;
public class UIAnimator : MonoBehaviour
{
private CanvasGroup _group;
void Awake() => _group = GetComponent<CanvasGroup>();
public void FadeOut(float duration)
{
StartCoroutine(FadeOutRoutine(duration));
}
private IEnumerator FadeOutRoutine(float duration)
{
float elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
_group.alpha = 1f - (elapsed / duration);
yield return null; // wait one frame
}
_group.alpha = 0f;
gameObject.SetActive(false);
}
public Coroutine DoAfterDelay(float delay, System.Action action)
{
return StartCoroutine(DelayedAction(delay, action));
}
private IEnumerator DelayedAction(float delay, System.Action action)
{
yield return new WaitForSeconds(delay);
action?.Invoke();
}
}코드 예제
고급코루틴 체이닝(yield return 다른 코루틴)과 WaitUntil.
using System.Collections;
using UnityEngine;
public class LevelTransition : MonoBehaviour
{
private bool _loadingDone = false;
private readonly WaitForSeconds _framePause = new(Time.fixedDeltaTime);
public void TransitionToNextLevel()
{
StartCoroutine(TransitionSequence());
}
private IEnumerator TransitionSequence()
{
// 1. Run another Coroutine and wait for it
yield return StartCoroutine(FadeToBlack(1.0f));
// 2. Load scene async
_loadingDone = false;
StartCoroutine(LoadSceneAsync());
// 3. Wait until load finishes (WaitUntil)
yield return new WaitUntil(() => _loadingDone);
// 4. Fade in the new scene
yield return StartCoroutine(FadeFromBlack(0.5f));
}
private IEnumerator LoadSceneAsync()
{
var op = UnityEngine.SceneManagement.SceneManager
.LoadSceneAsync("Level_02");
op.allowSceneActivation = false;
while (op.progress < 0.9f)
yield return null;
op.allowSceneActivation = true;
_loadingDone = true;
}
}📌 빠른 정리
- ▸
yield return null= 한 프레임 대기 - ▸
new WaitForSeconds(t)를 캐시——매 프레임 GC 방지 - ▸GO가 비활성/파괴되면 코루틴 중지
- ▸
yield return StartCoroutine()으로 체이닝
⚠️ 흔한 실수
❌ Coroutine 참조를 잊음
핸들 없이 StopCoroutine을 정확히 못 함
✅ _co = StartCoroutine(MyRoutine())
❌ while 루프 안에서 new WaitForSeconds()
매 반복 할당 → GC 스팸
✅ 캐시: var w = new WaitForSeconds(0.1f);