게임 로직을 짜다 보면 "특정 조건이 만족될 때까지 대기"해야 하는 상황이 정말 많이 발생합니다.
- 플레이어의 HP가 0이 될 때까지 대기
- 스페이스 바를 누를 때까지 대기
- 적들이 모두 사라질 때까지 대기
보통 우리는 Coroutine(코루틴)을 사용해 이 문제를 해결하는데요. 여러분은 이 코드를 어떻게 작성하고 계신가요? 오늘은 고전적인 방식과 유니티가 제공하는 조금 더 '우아한' 방식을 비교해 보겠습니다.
1. 고전적인 방식: while 루프와 yield return null
가장 흔하게 사용되는 패턴입니다. while 문으로 조건을 검사하고, 조건이 만족되지 않으면 yield return null을 통해 1 프레임을 쉬는 방식이죠.
예를 들어, 플레이어의 HP가 0 이하가 될 때까지 기다리는 코드는 보통 이렇게 작성합니다.
IEnumerator WaitForDeath_Classic()
{
Debug.Log("전투 시작! 죽을 때까지 기다립니다...");
// HP가 0보다 큰 동안 계속 루프를 돕니다.
while (playerHP > 0)
{
// 1 프레임 대기 후 다시 조건을 검사합니다.
yield return null;
}
Debug.Log("플레이어 사망! 게임 오버 처리를 시작합니다.");
}
이 방식의 단점?
사실 기능상으로는 전혀 문제가 없습니다. 하지만:
- 가독성:
while문 안에yield return null이 들어가는 구조가 매번 반복되어 코드가 길어집니다. - 의도 파악: 코드를 읽을 때 "이 루프가 도대체 무엇을 기다리는 것인가?"를 파악하기 위해 루프 내부 로직을 해석해야 할 때가 있습니다.
2. 우아한 방식: WaitUntil과 WaitWhile
유니티는 이러한 패턴을 더 직관적으로 작성할 수 있도록 WaitUntil과 WaitWhile이라는 클래스를 제공합니다. 이들은 델리게이트(Delegate) 를 인자로 받아 조건을 판단합니다.
1) WaitUntil: 조건이 True가 될 때까지 대기
말 그대로 "~할 때까지(Until)" 기다리는 것입니다. 괄호 안의 조건이 true가 되면 대기를 멈추고 다음 줄로 넘어갑니다.
위의 while 문 코드를 리팩토링해 볼까요?
IEnumerator WaitForDeath_Elegant()
{
Debug.Log("전투 시작! 죽을 때까지 기다립니다...");
// 플레이어의 HP가 0 이하가 될 때(True)까지 대기합니다.
yield return new WaitUntil(() => playerHP <= 0);
Debug.Log("플레이어 사망! 게임 오버 처리를 시작합니다.");
}
단 한 줄로 줄어들었습니다!() => playerHP <= 0 은 람다식(Lambda Expression)으로, "HP가 0 이하인가?"라는 조건을 실시간으로 체크합니다.
2) WaitWhile: 조건이 True인 동안 대기
이건 반대입니다. "~하는 동안(While)" 계속 기다리는 것입니다. 즉, 괄호 안의 조건이 false가 되어야 탈출합니다.
IEnumerator WaitForInput_Elegant()
{
Debug.Log("키 입력을 기다리는 중...");
// 스페이스 바를 누르지 않고 있는 동안(True) 계속 대기합니다.
// 즉, 스페이스 바를 누르면(False) 대기가 끝납니다.
yield return new WaitWhile(() => !Input.GetKeyDown(KeyCode.Space));
Debug.Log("스페이스 바 입력 확인!");
}
3. 비교 및 요약
| 특징 | 고전 방식 (while) |
우아한 방식 (WaitUntil / WaitWhile) |
|---|---|---|
| 구문 | while(조건) { yield return null; } |
yield return new WaitUntil(() => 조건); |
| 가독성 | 루프 구조로 인해 다소 김 | 영어 문장처럼 읽혀 직관적임 |
| 유연성 | 루프 내부에 추가 로직 넣기 쉬움 | 오직 '대기' 목적에 특화됨 |
| 성능 | 가비지 생성 없음 | new 키워드로 인한 미세한 가비지 생성 (무시할 수준) |
언제 무엇을 써야 할까?
- 단순히 "특정 상태가 변하길 기다리는 것"이 목적이라면
WaitUntil/WaitWhile을 쓰세요. 코드가 훨씬 깔끔해지고 "나는 지금 기다리는 중이다"라는 의도가 명확해집니다. - 기다리는 동안 매 프레임 다른 연산(예: 타이머 카운트 다운, 로그 출력 등)을 같이 해야 한다면 기존의
while문을 쓰는 것이 낫습니다.
마무리
코드는 컴퓨터가 읽는 글이기도 하지만, 동료(혹은 미래의 나)가 읽는 글이기도 합니다.
똑같은 기능을 하더라도 yield return new WaitUntil(() => isFinished);라고 적혀 있다면, 누구나 직관적으로 "아, 끝날 때까지 기다리는구나!"라고 이해할 수 있을 것입니다.
지금 작성 중인 코루틴에 불필요한 while 루프가 있다면, 오늘 한 번 리팩토링해 보는 건 어떨까요?
'Public' 카테고리의 다른 글
| [Unity/C#] 리플렉션은 왜 느리고, 왜 IL2CPP에서 위험한가 (0) | 2026.01.31 |
|---|---|
| [Unity\] On-Screen Stick 으로 모바일 조이스틱 구현하기 (0) | 2025.12.20 |
| [Unity] Prefab Variant vs Nested Prefab (1) | 2025.12.18 |
| [Unity] 프리팹 안의 프리팹 : Nested Prefab (중첩 프리팹) (0) | 2025.12.18 |
| [Unity] 프리팹 간에 상속이 가능하다고? Prefab Variant 활용법 (0) | 2025.12.11 |