성숙한 엔진이 없던 시절, 게임 회사들은 어떻게 게임을 "손수 제작"했을까?


이 질문에 대한 대답은 대부분의 사람들이 상상하는 것보다 훨씬 더 원시적이다.

오늘날의 게임 개발자들은 Unity나 Unreal을 열면 에디터가 있고, 물리 엔진이 있고, 렌더링 파이프라인이 있고, 조명 시스템이 있다. 그들의 작업은 이미 구축된 프레임워크 안에 콘텐츠를 채워 넣는 것이다. 이런 것은 1980년대에는 존재하지 않았다. 프레임워크도, 엔진도, 재사용 가능한 인프라도 없었다. 게임을 만들고 싶다면, 먼저 그 게임을 실행할 수 있는 기계를 만들어야 했고, 그 기계 위에서 어셈블리 언어로 모든 픽셀이 무슨 색이어야 하는지 하나하나 지정해야 했다.

모든 것은 픽셀에서 시작되었다.

초기 게임 그래픽은 메모리에 직접 기록되었다. 프로그래머들은 화면의 모든 위치에 해당하는 메모리 주소를 알고 있어야 했다. 특정 위치에 점을 찍으려면 그 주소에 값을 썼다. 그 값이 색상을 나타냈다. 선을 그리려면 루프를 작성하여 CPU에게 이 주소부터 저 주소까지 N바이트마다 쓰라고 지시했다. 캐릭터를 그리려면 각 픽셀 행을 16진수로 변환하고, 한 행씩 차례로 작성한 후, 화면에서 올바른 오프셋을 찾아 그 숫자들을 배치했다.

이 과정은 오늘날 “소프트웨어 렌더링”이라고 불린다. 그 당시에는 이름이 없었다. 대안이 없었기 때문이다 — 그냥 “화면이 어떻게 나오는지”라고 불렸다.

카맥이 첫 번째 Wolfenstein을 작업할 때, 그는 구체적인 문제에 직면했다. IBM PC의 그래픽 아키텍처는 부드러운 수평 스크롤을 지원하지 않았다. 화면은 프레임 전체를 한 번에 갱신하는 방식으로 업데이트되어, 이미지가 움직일 때 테어링이 발생했다 — 마치 떨리는 것처럼 보였다. 그는 GPU의 저수준 레지스터를 연구하는 데 엄청난 시간을 쏟았고, 하드웨어가 기본적으로 지원하지 않는 기능을 소프트웨어로 시뮬레이션하여 하드웨어를 속이는 방법을 찾아냈고, 화면이 부드럽게 스크롤될 수 있었다.

이에 대한 문서도, 선례도 없었다. 그는 그냥 앉아서 하드웨어 매뉴얼을 샅샅이 뒤지고, 시행착오를 통해 조금씩 알아냈다.

이것이 그 시대 프로그래머들의 기본적인 작업 조건이었다. 당신이 마주한 것은 설명서가 있는 시스템이 아니라 하드웨어 그 자체였다. 당신은 하드웨어보다 하드웨어를 더 잘 알아야 했고, 그 틈새에서 공간을 찾아내야 했다.

사운드는 완전히 다른 차원의 문제였다.

초기 PC의 사운드 시스템은 버저 — PC 스피커였다. 그것은 “삐” 소리 하나만 낼 수 있었다. 그것으로 음악을 재생하려면, 이 버저의 진동 주파수를 제어하고, 서로 다른 주파수를 극도로 빠른 속도로 전환하며, 인간 청각의 잔향 효과를 이용하여 멜로디가 재생되는 것처럼 들리게 만들어야 했다. 이 기술은 PWM, 펄스 폭 변조라고 불린다. 원리는 음향 물리학이고, 구현은 마이크로초 단위의 정밀한 타이밍 제어다. 조금만 잘못해도 그냥 소음만 나온다.

당시에는 PC 스피커에서 더 많은 음향 레이어를 짜내는 방법을專門 연구하는 프로그래머들이 있었다. 그 방법은 극도로 짧은 시간 창 안에서 서로 다른 주파수를 전환하여, 의사 스테레오 효과를 만드는 것이었다. 이 기술은 당시 데모 씬에서 흑마법처럼 취급되었다. “삐” 소리만 낼 수 있는 버저로 음악에 가까운 무언가를 만들어낸 것이다. 그것을 들은 다른 프로그래머들은 어떻게 한 것인지 전혀 알 수 없었다 — 원리가 직관적이지 않았기 때문이다. 그것을 실현하려면 타이밍 제어에 대한 극도로 정확한 이해가 필요했다.

Adlib과 Sound Blaster가 등장하면서 FM 합성 사운드가 생겼다. 이것은 또 다른 처음부터 배워야 할 시스템이었다. FM 합성의 원리는 한 주파수의 파형을 사용하여 다른 주파수의 파형을 변조하고, 복잡한 음색을 생성하는 것이다. 서로 다른 변조 매개변수가 서로 다른 악기 소리를 만들어냈다. 프로그래머들은 스스로 매개변수를 조정하고, 어떤 조합이 피아노처럼 들리고, 어떤 것이 바이올린처럼 들리고, 어떤 것이 폭발음처럼 들리는지 테스트해야 했다. 표준적인 정답은 없었다 — 모든 것은 귀와 경험에 의존했다. 당시 각 회사의 사운드 프로그래머들은 자신이 축적한 매개변수 테이블을 가지고 있었는데, 그것은 진정한 의미의 영업 비밀이었다.

게임 로직 수준에서의 디자인 감각은 또 다른 형태였다.

엔진이 없다는 것은 기성 충돌 감지, 기성 물리 시뮬레이션, 기성 AI 프레임워크가 없다는 뜻이었다. 캐릭터가 벽에 도달했을 때 벽을 통과하지 않고 멈추길 원한다면, 충돌 감지를 직접 작성하고, “충돌”이 무엇인지 직접 정의하고, 충돌 후 캐릭터의 속도와 위치가 어떻게 변할지 직접 결정해야 했다.

초기 게임의 충돌 감지는 단순하고 조잡했다. 캐릭터와 장애물을 모두 직사각형으로 보고, 두 직사각형이 겹치는지 확인하고, 겹치면 멈추는 방식이었다. 이 방식은 빨랐지만, 문제는 실제 게임 캐릭터가 직사각형이 아니라는 점이다 — 형태가 있는 스프라이트다. 직사각형 충돌 상자와 실제 그래픽 사이에는 항상 오차가 있었다. 그래서 초기 게임에서는 분명히 빗나간 총알이 여전히 명중으로 판정되거나, 캐릭터가 벽에 시각적으로 닿기도 전에 멈춰버리는 경우가 자주 발생했다.

당시 플레이어들은 이것을 버그라고 부르지 않았다. 게임의 특징이라고 불렀다. 다른 방식이 가능하다는 것을 몰랐기 때문이다.

또 한 가지 언급할 가치가 있는 것은, 초기 PC의 메모리가 극도로 제한적이었다는 점이다. 640KB는 10년 동안 하드웨어의 상한선이었다. 오늘날 이 숫자는 스크린샷 하나도 저장할 수 없다. 프로그래머들은 게임의 모든 것 — 그래픽, 음향 효과, 맵, 로직 코드 — 을 이 640KB 안에 쑤셔 넣고, 실행 시간 데이터를 위한 공간도 남겨두어야 했다.

어떻게? 압축, 분할 로딩, 재사용.

그래픽 데이터 압축은 독립적인 기술 분야였다. 프로그래머들은 자신만의 압축 알고리즘을 발명하여, 그래픽 데이터를 저장 시 가능한 한 작게 만들고, 표시가 필요할 때 즉시 압축 해제해야 했다. 맵이 너무 커서 들어가지 않으면 청크로 나누고, 플레이어가 있는 청크만 로드하고, 떠나면 언로드했다. 오늘날 이 기술은 스트리밍이라고 불린다. 그 당시에는 “어쩔 수 없음”이라고 불렸다.

메모리의 모든 바이트는 쟁탈전의 대상이었다. 코드를 작성할 때 프로그래머들은 끊임없이 생각해야 했다. 이 변수에 더 작은 데이터 타입을 사용할 수 있을까? 이 로직에 임시 변수를 더 적게 사용할 수 있을까? 이 루프의 메모리 액세스 횟수를 줄일 수 있을까? 이러한 사고 방식은 오늘날의 프로그래머들에게는 대부분 필요하지 않다. 현대의 하드웨어는 메모리 여유가 충분하고, 컴파일러는 최적화에 충분히 똑똑하다 — 바이트 하나하나를 셀 필요가 없다.

하지만 그 시대의 프로그래머들은 컴퓨터 전체의 작동 방식을 머릿속에 담고 있었다. CPU 명령어 사이클부터 메모리 레이아웃, GPU 레지스터에 이르기까지 모든 계층을 이해해야 했다. 모든 계층이 그들이 활용해야 할 틈새가 될 수 있었기 때문이다.

카맥은 역제곱근을 계산하는 코드를 작성한 적이 있는데, 그 안에는 “what the fuck”이라는 주석이 있었다. 이 코드는 직관에 반하는 비트 조작 트릭을 사용하여 역제곱근을 빠르게 근사 계산했으며, 표준 수학 라이브러리보다 훨씬 빨랐다 — 모두 3D 렌더링에서 계산 시간을 절약하기 위해서였다. 이 코드 조각은 나중에 프로그래머 문화의 전설이 되어 반복적으로 인용되었다. 하드웨어 제약 안에서 수학과 창의력으로 성능을 짜내는, 이미 사라진 사고 방식을 상징했기 때문이다.

그 시대의 게임 프로그래머들은 엔지니어와 과학자의 혼합체에 더 가까웠다. 그들이 해결한 문제는 단지 “기능을 어떻게 구현할까”가 아니라 “이 기계의 물리적 한계 안에서 그 기능을 구현할 수 있을까”였다.

이 두 질문은 매우 다르다.

첫 번째 질문에는 표준적인 답이 있다. 문서를 찾아보고, API를 호출하고, 절차를 따르면 된다. 두 번째 질문에는 표준적인 답이 없다. 스스로 답을 발명해야 한다. 때로는 답이 존재하고, 때로는 존재하지 않는다. 먼저 자신이 어떤 경우에 해당하는지 알아낸 다음, 어떻게 할지 결정해야 했다.

오늘날의 게임 산업은 거대한 협력 시스템이다. 엔진 회사, 미들웨어 회사, 툴체인 회사 — 모든 계층에 누군가가 작업하고 있다. 개발자는 이 시스템의 정상에 서서 콘텐츠 자체에 집중한다. 이것은 진보이며 좋은 일이다 — 더 많은 사람들이 게임을 만들 수 있게 하고, 게임의 규모와 복잡성이 과거에 비해 훨씬 더 커질 수 있게 한다.

하지만 픽셀에서부터 게임을 구축하던 그 시대에는 오늘날 더 이상 존재하지 않는 무언가가 있었다.

게임을 열면, 화면의 모든 점이 어디서 왔는지, 모든 소리가 어떻게 만들어졌는지, 모든 충돌이 어떻게 판정되었는지 알 수 있다. 그것들은 모두 당신이 한 줄 한 줄 직접 작성한 것이며, 다른 누군가가 대신해준 것은 아무것도 없기 때문이다.

이 느낌에는 이름이 있다. 그것은 완전한 통제감이라고 불린다.

그러니 그 시대에 게임을 개발한 대가들은 — 진정한 대가였다. 정말 대단했다.