게임 엔진을 위해 코루틴을 만들었지만, 결국 사용하지 않았다

게임 엔진을 위한 제너레이터 코루틴 시스템을 구축했습니다. 코드 122줄과 12개의 테스트로 이루어진 시스템이었죠. 이 시스템은 콜백 지옥 문제를 해결했고, 스크립트를 마치 직선처럼 읽기 쉽게 만들어 주었습니다.

하지만 저는 게임 로직에 이 시스템을 사용하지 않기로 했습니다. 대신 유한 상태 머신(FSM)을 사용했습니다.

그 이유는 다음과 같습니다.

대부분의 튜토리얼은 실시간 게임에서 제너레이터가 가진 두 가지 거대한 문제, 즉 메모리와 저장(saving) 문제를 간과합니다.

1. 메모리 압박

제너레이터에서 .next()를 호출할 때마다 JavaScript 엔진은 새로운 객체를 생성합니다. 이 객체에는 현재 값과 상태가 포함됩니다.

60 FPS로 실행되는 게임 루프에서 이는 지속적인 가비지 컬렉션(GC) 부하를 일으킵니다. 제 엔진은 성능을 안정적으로 유지하기 위해 '제로 할당(zero-allocation)' 규칙을 따릅니다. 제너레이터는 이 규칙을 깨뜨립니다. 매 프레임마다 작은 객체들을 끊임없이 생성하기 때문입니다.

2. 직렬화 문제

게임에는 저장과 불러오기 기능이 필요합니다. 현재 게임 상태를 데이터로 변환했다가 다시 복구할 수 있어야 합니다.

일시 중지된 제너레이터는 직렬화할 수 없습니다. 그 상태는 접근할 수 없는 엔진 내부 슬롯에 존재하기 때문입니다. 저장을 시도하면 빈 객체가 나오거나 에러가 발생합니다.

유한 상태 머신(FSM)은 다릅니다. 상태가 컴포넌트 위의 단순한 문자열일 뿐입니다.

  • 저장할 때: 문자열을 디스크에 씁니다.
  • 불러올 때: 문자열을 읽고 FSM에 해당 지점부터 시작하라고 명령합니다.

FSM이 선택된 이유는 전문적인 게임에서 가장 중요한 두 가지, 즉 성능과 데이터 지속성(persistence)을 완벽히 처리할 수 있기 때문입니다.


선택 기준:

로직이 메인 프레임 루프 안에 있는가?

  • 아니오: 제너레이터 코루틴을 사용하세요. 에셋 로딩이나 온보딩 같은 일회성 흐름에는 아주 좋습니다.
  • 예: 다음 질문으로 넘어갑니다.

상태가 저장 시에도 유지되어야 하는가?

  • 예: 유한 상태 머신(FSM)을 사용하세요.
  • 아니오: 다음 질문으로 넘어갑니다.

동시에 많은 시퀀스를 실행 중인가?

  • 예: 유한 상태 머신(FSM)을 사용하세요.
  • 아니오: 제너레이터 코루틴을 사용하세요.

제너레이터가 틀린 것은 아닙니다. 단지 '핫 패스(hot path)'에는 맞지 않는 도구일 뿐입니다. 비동기 연결(async glue) 용도로는 사용하되, 게임 로직에는 FSM을 사용하세요.

Source: https://dev.to/grzott/i-built-generator-coroutines-for-my-game-engine-then-didnt-use-them-o3g