16MHz에서 도시 건설 게임을 돌리는 법

How to run a city builder on 16 MHz

larstofus.com ▲ 90 댓글 25 rex64

요약

1989년 SimCity는 시뮬레이션 작업을 16프레임에 나눠 돌려서 16MHz CPU로도 도시 전체를 굴렸습니다.

게임 프로그래밍 블로그 Larst Of Us의 글입니다. 글쓴이는 2008년 GPL로 공개된 SimCity 소스 코드(Micropolis)를 살펴보며, 386SX를 요구 사양으로 내건 게임이 도시 경제 전체를 시뮬레이션할 수 있었던 비결을 정리했습니다.

왜 중요한가

  • 모든 코드를 매 프레임 돌릴 필요는 없다는 발상만으로 느린 하드웨어의 한계를 넘을 수 있음을 보여 줍니다.
  • 주로 렌더링에서 쓰던 작업 분산 기법이 게임 로직에도 통한다는 점을 실제 코드로 확인시켜 줍니다.

핵심 내용

  • 핵심 시뮬레이션 함수 Simulate()는 매 프레임 불리지만, 0부터 15까지 도는 mod16 값에 따라 그 프레임의 일만 골라 실행합니다.
  • 그래서 범죄 분석, 화재 분석, 세금 징수 같은 작업이 프레임마다 번갈아 돌아갑니다.
  • 플레이어의 행동에 각 시스템이 반응하기까지 평균 8프레임, 최악에는 15프레임이 걸립니다.
  • 슈팅 게임이라면 치명적인 지연이지만, 도시 시뮬레이션에서는 즉각 반응보다 오히려 자연스러울 수 있다고 봤습니다.
  • 레이싱 게임 Assetto Corsa도 반사용 큐브맵(주변 풍경을 6면에 담은 텍스처)을 프레임마다 몇 면씩만 갱신합니다.

HN 반응

  • 비행 시뮬레이터 업계가 수십 년 전부터 '밴딩'이라는 이름으로 쓰던 오래된 기법이라는 경험담과, 옛 기계라면 당연한 방식이라는 반응이 이어졌습니다.
  • 386SX가 필요했다는 글의 전제에는 Commodore 64(1MHz)나 BBC Micro(2MHz)판도 핵심 시뮬레이션을 돌렸다는 반론이 나왔습니다.

댓글

19개 표시 · 전체 25개
  1. prosaic-hacker HN

    좋은 깨달음이지만, 아주 오래전부터 쓰이던 기법입니다. 제가 대학을 졸업하고 처음 프로그래머로 일한 곳이 비행 시뮬레이터 회사인 CAE Electronics였습니다. 시뮬레이션은 당시의 여러 미니컴퓨터에서 돌아갔고, 제가 있던 동안에는 주로 DEC VAX 780과 그 후속기, 아니면 Gould SEL이었습니다.

    제 기억이 맞다면 시뮬레이션은 마이크로컨트롤러의 슈퍼 루프처럼 50ms나 33ms마다 한 바퀴씩 돌았습니다. 루프가 돌 때마다 디스패처가 핵심 시뮬레이션 함수 몇 개를 골라 실행했는데, 어떤 것은 매 루프마다, 어떤 것은 2번째, 4번째, 혹은 그 이상 간격의 루프마다 실행했습니다. 이 방식을 밴딩(banding)이라고 불렀습니다. 디스패치 테이블은 시뮬레이터마다 필요에 맞게 새로 짰습니다.

    메인 CPU 바깥에서도 여러 최적화가 있었습니다. 주변 장치들도 계산을 맡았거든요. 또 시스템이 빨라지면서 시간이 남게 되자, 일반 OS가 실시간성이 필요 없는 낮은 우선순위 작업을 돌릴 수 있게 되었습니다.

    이 기법은 제가 일하던 때에도 새로운 것이 아니었고, 약 10년 전 세대의 Xerox 시스템에서도 이미 쓰였습니다.

  2. altcognito HN

    저도 이 글과 같은 시대의 기계에서 일해 봤는데, 성능이 부족하던 옛날로 거슬러 올라갈수록 이 기법이 흔했을 거라고 생각합니다. CPU 시분할의 변형일 뿐이죠.

  3. hansor HN

    재미있는 이야기 하나 해드리죠. 1978년에 나온 VAX 780을 지금도(2026년이에요!) NetBSD 최신 버전이 지원한다는 거 아세요? :D

    MMU를 갖춘 최초의 현대적 32비트 CPU였죠.

  4. phire HN

    예를 들어 오리지널 심시티는 시스템 요구 사양에 CPU로 인텔 386SX를 적어 두었습니다.

    이게 어디서 나온 얘긴지 모르겠네요. 오리지널 출시 박스 아트[1]에는 RAM 512KB인 PC면 어디서든 돌아간다고 적혀 있습니다. 그러면 겨우 4.77MHz로 도는 8088이라는 얘기입니다.

    하지만 그것도 이 게임의 최저 사양 이식작과는 거리가 멉니다. Commodore 64 버전은 경기장, 경찰서/소방서, 철도 같은 기능이 꽤 빠져 있긴 해도, 핵심인 도시 시뮬레이션 루프는 겨우 64KB RAM과 1MHz 6502에서 돌았습니다.

    BBC Micro/Acorn Electron 이식작은 그보다 더 인상적이었습니다. 음악/소리/애니메이션만 빠졌을 뿐 Amiga/PC/Mac 정식 버전의 기능을 사실상 전부 갖췄거든요. 2MHz 6502(Electron은 1MHz)에 RAM은 겨우 32KB였는데도요.

    [1] https://images.launchbox-app.com/79861ce4-75ea-46dd-b46e-52185346e7ab.jpg

  5. no-name-here HN

    저도 이 글이 HN 첫 페이지에 올랐길래 훨씬 자세한 내용을 기대했는데, 결국 게임이 16프레임 주기로 돌아가서 한 프레임에서는 범죄 관련 처리를, 다른 프레임에서는 화재와 재난 관련 처리를 하는 식이라는 게 전부더군요. 프레임 하나 안에서 무슨 일이 일어나는지는 설명이 없고, 함수 이름 다섯 개 말고는 아무것도 없습니다. 소스는 https://www.donhopkins.com/home/micropolis/ 에 있습니다.

  6. vidarh HN

    오리지널은 Amiga와 Mac용으로 나왔습니다. C64 버전은 PC 버전과 비슷한 시기에 뒤따라 나왔는데, 알려진 바로는 C64 버전이 원조였다고 합니다.

  7. Max-q HN

    C64 버전은 이식작이 아니에요. C64 버전이 원조입니다.

  8. retrac HN

    Game Boy Color용 심시티 클론인 microcity가 생각나네요.

    제작자가 설계에 관한 훌륭하고 깊이 있는 문서를 남겼는데, 8MHz 8비트 프로세서가 달린 기계에 제법 활기찬 시뮬레이션을 어떻게 집어넣었는지 알 수 있습니다.

    https://github.com/AntonioND/ucity/blob/master/docs/index.rst

  9. anthk HN

    GBC는 그래픽이 NES 상급과 SNES의 중간쯤이라는 점을 염두에 두셔야 합니다.

  10. sgt HN

    요즘은 가장 싼 CPU조차 코어가 적어도 4개이고, 초당 수십억 번의 연산을 실행합니다.

    그런데 요즘 프로그램은 지연 시간과 응답 시간이 수십, 수백 밀리초씩 걸리는 경우가 많다는 게 아이러니합니다. 이유야 알지만 그래도 생각해 보면 좀 어이없어요. 우리가 겹겹이 쌓아 올린 추상화 계층 때문이죠.

  11. RetroTechie HN

    이제 느린 CPU는 없어요. 1달러도 안 하는 마이크로컨트롤러조차 30년 넘게 전에 제가 Gradius를 하던 기계보다 훨씬 빠릅니다.

    그런데도 오늘날의 컴퓨터를 느리게 만드는 소프트웨어 개발자는 차고 넘치죠. 그냥 생각인데, 그런 사람들을 Real Programmers (tm)로 갈아치우면 어떨까요?

  12. pelcg HN

    이게 전부 16MHz 기계에서 돌아갔는데, 요즘 32GB RAM 컴퓨터에서는 Java나 심지어 Electron을 쓰는 메모리 먹보 데스크톱 앱들이 널려 있습니다.

    요즘은 JavaScript로 만든 텍스트 에디터도 Electron을 쓰면 1GB 넘게 먹습니다. 사용자가 문서를 여러 개 열어서 RAM 사용량이 더 늘어나는 경우는 따지지도 않은 건데요.

  13. anthk HN

    저는 제 컴퓨터(amd64, 8GB, Pentium Silver N5030)에서 Electron이라는 쓰레기는 전부 금지했습니다. 지금은 Rust 프로그래밍용 IDE로 Rust+Tauri로 만든 VS Code 클론을 써 보는 중이에요. 반쯤은 Electron이지만 훨씬 가볍습니다.

  14. adventured HN

    제가 사는 곳은 물이 풍부합니다. 가뭄은 사실상 한 번도 일어나지 않아요. 샤워를 5분 하든 15분 하든 신경 쓸 일이 없죠. 그러니 이곳 사람들이 대체로 물 사용량을 걱정하지 않는 건 심각한 사막 환경처럼 물이 귀한 곳과는 다르다는 걸 짐작하실 겁니다.

    요즘 애플리케이션 상당수가 자원을 낭비하는 거대한 덩어리가 된 것도 같은 이유입니다. 우리에게는 오랫동안 자원이 남아돌았거든요.

    물론 자원 낭비를 둘러싼 도덕적 논쟁은 제쳐 두고 하는 말입니다. 그건 별개의 논의니까요. 이유는 이렇습니다. 태워도 될 만큼 자원이 있었으니 태우는 겁니다. 대체로 자원 사용량은 꼭 필요한 만큼만 빡빡해지는 법입니다.

  15. a1r HN

    오, 방금 알았는데 C64의 SHADOWFIRE는 프레임마다 캐릭터를 하나씩만 갱신하는 방식으로 서로 다른 캐릭터 50명을 시뮬레이션한다고 하네요. 그래서 PAL TV의 주사율에 맞추느라 한계가 50명이라고 합니다.

    https://gamesexplained.com/c64/shadowfire/#people

  16. santix HN
  17. DonHopkins HN

    링크 감사합니다! 그건 원래 micropolis 저장소와 OLPC 릴리스에 있던 옛 C/TCL/Tk 코드입니다. 최신 버전은 이름과 주석을 더 낫게 다듬어 C++로 옮긴 코드이고, 새 MicropolisCore 저장소에 있습니다.

    https://github.com/SimHacker/MicropolisCore/blob/main/packages/micropolis-engine/src/simulate.cpp#L132

    Chaim Gingold가 "Building SimCity"에 관한 책을 썼습니다.

    https://mitpress.mit.edu/9780262547482/building-simcity/

    그는 이 HN 토론에서 책에 관한 질문에 답해 주었습니다.

    https://news.ycombinator.com/item?id=40698442

    기사보다 더 자세한 내용이 궁금하시다면, Chaim Gingold는 자신의 책 "Building SimCity: How to Put the World in a Machine"(MIT Press, 2024)을 위해 이 루프 전체를 그림으로 그렸고, 고맙게도 그 도표를 MicropolisCore 저장소에 넣도록 허락해 주었습니다.

    Chaim Gingold의 "SimCity Reverse Diagrams":

    https://github.com/SimHacker/MicropolisCore/tree/main/images/diagrams

    시뮬레이션 루프(Simulate):

    https://github.com/SimHacker/MicropolisCore/blob/main/images/diagrams/SimCityReverseDiagrams-Page-1-Simulate.png

    맵 데이터 흐름(Map Data Flow):

    https://github.com/SimHacker/MicropolisCore/blob/main/images/diagrams/SimCityReverseDiagrams-Page-2-Map-Data-Flow.png

    맵(Maps):

    https://github.com/SimHacker/MicropolisCore/blob/main/images/diagrams/SimCityReverseDiagrams-Page-3-Maps.png

    맵 스캔(Map Scan):

    https://github.com/SimHacker/MicropolisCore/blob/main/images/diagrams/SimCityReverseDiagrams-Page-4-Map-Scan.png

    교통 생성(Make Traffic):

    https://github.com/SimHacker/MicropolisCore/blob/main/images/diagrams/SimCityReverseDiagrams-Page-5-Make-Traffic.png

    애니메이션 캐릭터(Animation Characters):

    https://github.com/SimHacker/MicropolisCore/blob/main/images/diagrams/SimCityReverseDiagrams-Page-6-Animation-Characters.png

    micropolis 저장소 README에서 가져온 내용입니다.

    참고: MicropolisCore를 보세요.

    https://github.com/SimHacker/MicropolisCore

    이 "micropolis" 저장소는 주로 역사적 기록용이고, 개발에는 새 MicropolisCore 저장소를 쓰는 편이 아마 더 낫습니다.

    저는 옛 X11/TCL/Tk 요소를 전부 걷어내고 micropolis를 새 MicropolisCore 저장소로 다시 띄웠습니다.

    MicropolisCore는 원래의 C 코드를 사용자 인터페이스와 무관한 시뮬레이션 엔진으로 C++로 다시 쓰고 정리한 것입니다.

    코드의 전체 계보는 이렇습니다. C64 => Mac => SunOS/NeWS/HyperLook => Unix/X11/TCL/Tk + 멀티플레이어 => Linux/X11/TCL/Tk + 멀티플레이어 => OLPC/X11/TCL/Tk (싱글 플레이어) => C++ MicropolisCore => C++/SWIG/Python/PyGTK => C++/SWIG/Python/TurboGears/AMF/Flash/OpenLaszlo => C++/Emscripten/Embind/TypeScript/SvelteKit.

    이제 emscripten/embind로 WASM에 컴파일되고, node에서 "헤드리스"로 돌리거나 브라우저에서 아무 종류의 사용자 인터페이스와도 함께 쓸 수 있습니다.

    그러니 새로 뭔가 만드신다면 MicropolisCore를 쓰는 게 좋지만, 레트로 컴퓨팅에 관심이 있어서 TCL 버전이나 옛 PyGTK 버전, 혹은 Python/TurboGears/AMF/Flash/OpenLaszlo 버전을 되살리고 싶으시다면 이 저장소에 필요한 게 다 있습니다!


    작업 중인 라이브 데모입니다(UI는 아직 못 끝냈지만 시뮬레이터와 타일 엔진은 돌아갑니다).

    https://micropolisweb.com/

    영상 데모:

    https://www.youtube.com/watch?v=wlHGfNlE8Os

    제리 마틴의 차분한 결의에 맞춘 심시티 Micropolis 타일셋, 공간 목록, 셀룰러 오토마타:

    https://www.youtube.com/watch?v=319i7slXcbI

  18. erickhill HN

    더 빠른 해결책도 있어요. 게다가 7MHz에서요. Amiga를 쓰세요.

  19. dyauspitr HN

    16MHz라니 대단하네요. 제가 처음 가졌던 윈도 3.1 컴퓨터가 그래도 33MHz였거든요.

Hacker News에서 보기 ↗