5P by GN⁺ 17시간전 | ★ favorite | 댓글 1개
  • 1999년작 RollerCoaster Tycoon은 거의 전부 어셈블리어로 작성된 시뮬레이션 게임으로, 수천 명의 손님을 실시간으로 처리하면서도 안정적인 성능을 유지
  • 개발자 Chris Sawyer는 고수준 언어 대신 저수준 제어를 택해, CPU 연산 효율을 극대화한 마지막 세대의 어셈블리어 게임을 완성
  • 팬 프로젝트 OpenRCT2를 통해 원본의 정밀한 최적화 패턴과 메모리 절약 기법이 역공학적으로 분석됨
  • 게임은 비트 시프트 연산과 데이터 타입 세분화를 활용해 연산 속도와 캐시 효율을 높였으며, 경로 탐색 깊이 제한충돌 연산 제거로 대규모 시뮬레이션을 가능하게 함
  • 이러한 구조는 기술적 제약을 창의적으로 활용한 최적화의 전형으로, 오늘날에도 설계 단계에서 불필요한 연산을 제거하는 접근의 중요성을 보여줌

RollerCoaster Tycoon의 최적화 구조 분석

  • 1999년 출시된 RollerCoaster Tycoon(RCT) 은 거의 전부 어셈블리어(Assembly) 로 작성되어, 수천 명의 에이전트를 실시간으로 시뮬레이션하면서도 당시 하드웨어에서 안정적인 프레임을 유지한 게임으로 평가됨
  • 독일 게임 팟캐스트 Stay Forever 에서 다룬 내용을 기반으로, Chris Sawyer 가 어떻게 극단적인 수준의 최적화를 달성했는지를 구체적으로 분석함
  • 원본 소스코드는 공개되지 않았지만, 팬들이 제작한 OpenRCT2 프로젝트를 통해 코드 구조와 최적화 기법을 역공학적으로 확인할 수 있음
  • 어셈블리어 기반의 성능 극대화

    • RCT는 C나 C++ 대신 어셈블리어로 작성되어, 당시 다른 게임보다 훨씬 세밀한 성능 제어가 가능했음
      • 예를 들어, Doom (1993)은 대부분 C로 작성되었으나, RCT는 거의 전부 어셈블리어로 구현됨
      • 이 접근은 1990년대 후반에는 이미 드문 방식이었으며, RCT는 마지막 대형 어셈블리어 게임 중 하나로 평가됨
    • 당시에는 컴파일러의 자동 최적화가 제한적이었기 때문에, 수동 최적화가 성능에 큰 차이를 만들었음
  • OpenRCT2를 통한 코드 분석

    • OpenRCT2 는 팬들이 원본 게임을 완전히 재구현한 오픈소스 프로젝트로, 원본 자산을 그대로 사용하면서도 100% 호환성을 유지함
      • 초기 버전은 원본 코드와 거의 동일한 동작을 재현했으며, 이후 다양한 개선이 추가됨
    • 이 프로젝트를 통해 원본 코드의 세밀한 최적화 패턴을 확인할 수 있었음
  • 데이터 타입의 세분화 — 메모리 절약

    • RCT는 금액 데이터의 크기를 상황별로 다르게 저장
      • 예: 전체 공원 가치는 4바이트 변수 사용, 상점 가격은 1바이트 변수 사용
    • 이러한 세분화는 메모리 절약과 캐시 효율 향상을 위한 것으로, 현대 CPU에서는 성능 차이가 거의 없어 OpenRCT2에서는 단일 8바이트 변수로 통일됨
  • 비트 시프트를 이용한 수학 연산 최적화

    • 코드에는 NewValue = OldValue > 연산은 2의 거듭제곱으로 나누는 연산을 대체함
    • 이러한 최적화는 곱셈·나눗셈이 2의 거듭제곱일 때만 가능하므로, 게임 내 수식 자체가 이 조건에 맞게 설계된 것으로 보임
    • 즉, 게임 디자인 단계에서부터 CPU 연산 효율을 고려한 수학 구조가 사용된 셈임
  • 성능을 고려한 게임 디자인

    • RCT는 Chris Sawyer가 프로그래머이자 유일한 게임 디자이너로 참여했기 때문에, 설계 단계에서부터 성능을 고려한 구조를 만들 수 있었음
    • 대표적 사례는 손님(Pathfinding) 시스템
      • 대부분의 시뮬레이션 게임은 손님이 목적지를 정하고 경로를 탐색하지만, RCT에서는 손님이 무작위로 걷다가 우연히 놀이기구를 발견함
      • 이 방식은 대규모 경로 탐색 연산을 피하는 구조로, 수천 명의 손님을 동시에 처리할 수 있게 함
    • 경로 탐색이 필요한 경우(예: 정비공이 고장난 놀이기구로 이동)는 탐색 깊이 제한을 두어 프레임 드랍을 방지함
      • 일반 손님은 5개의 교차로까지만 탐색, 정비공은 8개까지 탐색
      • 지도를 구매한 손님은 탐색 한도가 7로 증가함
    • 이러한 제한은 단순한 기술적 절충이 아니라, 게임플레이 요소로 자연스럽게 통합된 최적화 구조
  • 군중 처리와 충돌 회피 생략

    • RCT는 손님 간 충돌이나 회피 연산을 완전히 제거
      • 수천 명의 손님이 동일한 경로 타일을 공유할 수 있음
    • 대신, 주변 인구 밀도를 추적하여 혼잡도가 높으면 손님의 행복도가 감소하도록 설계됨
      • 플레이어는 여전히 혼잡을 관리해야 하지만, 계산량은 훨씬 적음
    • 이 방식은 복잡한 물리 연산을 제거하면서도 게임 경험을 유지한 대표적 사례로 평가됨
  • 현대 개발에 주는 시사점

    • RCT의 최적화는 기술적 제약을 창의적으로 활용한 사례로 평가됨
    • 오늘날에도 이러한 접근은 가능하지만, 프로그래머와 디자이너 간의 긴밀한 협업이 필요함
    • 때로는 기술적 문제를 해결하기보다, 문제 자체를 설계 단계에서 제거하는 접근이 더 큰 성능 향상을 가져올 수 있음
Hacker News 의견들
  • Warcraft 1, 2, StarCraft 모두 2의 거듭제곱 단위 맵 크기를 사용했음
    덕분에 느린 386/486 CPU에서도 나눗셈·곱셈 대신 시프트 연산으로 속도를 확보할 수 있었음
    맵 렌더링, 스프라이트, 폰트, 안개 효과 등은 수천 줄의 어셈블리로 처리했고, 나머지는 C로 작성된 이식성 높은 코드였음
    Blackthorne의 경우 SNES, Genesis, DOS 버전이 각각 다른 어셈블리로 수작업 포팅되었고, PC 버전은 VGA Mode X를 위해 10만 줄의 렌더링 코드를 매크로로 생성했음
    이런 경험 덕분에 Blizzard에서는 “어셈블리는 너무 많은 개발 시간을 잡아먹는다”는 교훈을 얻었음
    Comanche: Maximum Overkill은 전부 어셈블리로 작성된 보텍스 기반 헬기 시뮬레이터였는데, 보호 모드로 포팅이 너무 힘들어 이후 버전부터 폴리곤 렌더링으로 전환했음

    • Reddit 사용자가 StarCraft 골드 마스터 소스코드를 발견했지만, Blizzard 굿즈와 교환하며 반환한 게 아쉬움
      EA는 Command & Conquer 시리즈 소스코드를 공개했는데, Tiberian Sun과 Red Alert 2는 빠져 있었음
      StarCraft도 역사 보존 차원에서 공개되었으면 좋았을 것 같음
    • 어릴 적 Comanche와 Settlers 1을 처음 봤을 때 DOS 텍스트 모드에서 그래픽이 나오는 게 마법 같았음
      그때부터 게임에 완전히 빠져들었음
    • 혹시 Lost Vikings에도 참여했다면, 어린 시절의 즐거움을 줘서 고맙다는 말을 전하고 싶음
      혹시 데모씬(demoscene) 활동도 했는지 궁금함
    • Blizzard에 있을 때 소스코드 서버를 잃어버리고 백업도 없던 사건이 있었는데, 그 시기에 있었는지 궁금함
      나는 WC3 출시 즈음 컨설턴트로 잠시 있었음
    • Maximum Overkill은 정말 수백 시간을 플레이할 만큼 놀라운 게임이었음
  • 글에서 언급된 것처럼, 디자이너와 프로그래머가 동일인일 때 훨씬 인상적인 결과물이 나오는 것 같음
    대기업의 계층적 구조로도 결국은 인력으로 밀어붙이면 뭔가 나오긴 하지만, 진짜 창의적인 결과는 한 사람의 머리에서부터 완성되는 경우가 많음
    AI 개발 도구의 미래도 이런 ‘1인 개발 시대’로 회귀할지도 모른다는 생각이 듦

  • 게임 디자이너도 여전히 수치적 특성을 고려해야 함
    좋은 디자이너일수록 연산 효율이나 정밀도 같은 요소가 게임 밸런스에 영향을 준다는 걸 알고 있음
    요즘은 이런 걸 무시하는 개발자도 많지만, 그게 게임 품질 저하의 숨은 원인이 되기도 함

    • 예전엔 나도 이런 미세 최적화가 중요하다고 생각했지만, 현대 CPU의 파이프라인 구조를 공부하고 생각이 바뀌었음
      지금은 덧셈 1사이클, 곱셈 3사이클, 나눗셈 12사이클 수준이고, 동시에 여러 연산을 병렬로 처리함
      예전 펜티엄 시절엔 46사이클이 걸렸고 클럭도 100MHz였음
      지금은 메모리 레이아웃이 훨씬 중요함 — 캐시 미스 한 번이면 100~1000사이클이 날아감
      int[]로 연산하는 게 Monster[]보다 훨씬 빠름
    • 나는 csgrs CAD 커널을 개발 중인데, 숫자 계산은 아직도 풀리지 않은 문제라고 느낌
      속도, 정확도, 저장 크기, 복잡도 사이의 트레이드오프가 존재함
      Toward an API for the Real Numbers 같은 논문은 이런 문제를 단계적으로 해결하려는 접근을 제시함
      부동소수점 오차, 구간 산술, 심볼릭 연산 등 다양한 방법이 있지만, 결국 트레이드오프를 이해하지 못하면 문제에 물림
    • 상업 게임은 대량 생산되는 제품이므로, 디자이너가 기술적 제약을 이해하는 건 산업 디자인 감각으로서 큰 장점임
      예를 들어 Fumito Ueda는 『Shadow of the Colossus』에서 기술적 실현 가능성을 세심히 고려했고, Doom도 창의성과 기술의 결합이었음
      관련 인터뷰 참고
    • 게임 품질은 단순히 효율적인 런타임 성능이 아니라 재미와 완성도의 문제임
      버그, 스토리 일관성, 몰입감이 더 중요함
      물론 프레임 드랍이 심하면 품질 저하지만, 타깃 하드웨어에서 부드럽게 돌아간다면 개선은 다른 부분에 집중해야 함
    • ARM Cortex-M4 기반 제품을 개발할 때 커스텀 난수 생성기를 만들었음
      Thumb-2 명령어로 상수를 즉시 로드할 수 있게 조정해 메모리 스톨을 피했음
      덕분에 빠르고 효율적으로 난수를 사용할 수 있었고, 테스트도 모두 통과했음
      하지만 나중에 Cortex-M0로 바뀌면서 이 코드는 폐기되었음
  • 기술적 제약을 게임플레이 요소로 전환하는 부분이 흥미로웠음
    『젤다의 전설』의 Blood Moon 시스템이 떠오름

  • “/8 대신 >>3을 쓰면 나눗셈을 절약할 수 있다”는 설명은 현대 컴파일러에서는 사실이 아님
    타입이 맞다면 컴파일러가 자동으로 시프트 연산으로 최적화함

    • 단, 부호 있는 정수(signed) 의 경우는 C 표준의 반올림 규칙을 맞추기 위해 추가 연산이 들어감
  • “이진수에서 왼쪽 시프트는 두 배가 된다”는 설명을 보고 놀랐음
    2026년에 이런 기본 개념이 새삼스러울 정도로 낯설게 느껴지는 게 신기함

  • “컴파일러가 2의 거듭제곱 곱셈을 시프트로 바꾸지 않는다”는 말은 오래된 농담임
    2000년대에도 이미 컴파일러가 그런 코드를 보면 하품할 정도로 당연히 최적화함

  • 재미있게 읽었음. RCT 관련해서는 아래 자료들도 추천함

  • 대형 스튜디오에서 기술적 제약을 게임의 특징으로 승화시키는 게 가능한지 궁금함
    스토리텔링에서도 장애물이 이야기를 흥미롭게 만들듯, 1인 개발자는 기술적 한계를 창의적 요소로 전환할 수 있음
    예를 들어 버그나 글리치를 미니게임으로 재해석하는 식의 접근이 떠오름

  • RCT의 경로 탐색(pathfinding) 부분을 보며 Marcel Vos의 유튜브 영상이 생각났음
    그는 RCT의 내부 동작을 깊이 파헤치는 영상들을 많이 올림