「우리 길드 정상 영업합니다」는 모험가가 찾아오는 길드를 짓고 운영하는 3D 경영 건설 게임입니다. 건물 편집·모험가 이동·의뢰·인사·경제가 같은 시간 안에서 작동해야 합니다. 화면을 바꾸는 작업과 운영 규칙을 바꾸는 작업이 서로 미치는 영향을 줄이기 위해, 시뮬레이션과 표현의 책임을 먼저 나눴습니다.
이 글은 2026년 10월 23일 확인한 코드와 업데이트 2까지의 구현 문서를 기준으로 정리한 개발 기록입니다. 엔진 간 성능 비교 실험이나 모든 장르에 적용되는 권장 구성은 아닙니다. Steam 연동처럼 이후 별도 작업 중인 기능은 이 아키텍처의 완성 조건에 포함하지 않습니다.
구성 요약과 책임 경계
| 영역 | 선택 | 선정 이유 | 감수한 한계 |
|---|---|---|---|
| 엔진·화면 | Godot 4·GDScript | 장면·3D 표현·UI·입력을 같은 프로젝트에서 구성합니다. | 엔진 API 와 렌더러 호환성을 계속 확인해야 합니다. |
| 시뮬레이션 | C++20·godot-cpp GDExtension | 운영 규칙과 경로 탐색을 화면과 분리하고 네이티브 코드로 구현합니다. | 컴파일 도구·DLL·바인딩 관리가 추가됩니다. |
| 상태 관리 | Flecs ECS | 모험가·이동체·가구의 데이터와 처리 대상을 일관되게 관리합니다. | 게임의 모든 규칙이 ECS 시스템만으로 구성되는 것은 아닙니다. |
| 길찾기 | 국소 A*·HPA*·A* 대체 경로 | 짧은 이동과 긴 이동에 다른 탐색 경로를 사용합니다. | 건설로 통행 조건이 바뀌면 캐시·연결 정보 관리가 필요합니다. |
| 콘텐츠 | JSON·DefDatabase | 규칙 수치·시설·직업·표시 이름을 데이터로 관리합니다. | 새 규칙 자체는 코드를 추가해야 하며 데이터 검증도 필요합니다. |
| 지형·표현 | 자체 청크 메시·절차적 모델 | 타일 규칙과 실제 보이는 형상을 같은 기준으로 구성합니다. | 범용 복셀 편집과 수작업 모델 수준의 표현을 함께 제공하지 않습니다. |
| 저장 | 버전이 있는 JSON | 운영 상태를 확인하고 이전 저장의 기본값을 처리하기 쉽습니다. | 형식 변경마다 이관·왕복 검증을 해야 합니다. |
Godot 와 GDScript: 화면 구성과 빠른 수정
이 프로젝트에는 회전·이동 카메라, 바닥·벽·가구 편집, 창과 패널, 지하 층 표시가 필요합니다. Godot 의 장면과 노드를 사용하면 이 요소를 같은 편집·실행 환경에서 조합할 수 있습니다. GDScript 는 UI·카메라·표시 갱신에 사용하고, 시설 효과나 급여 같은 운영 규칙은 C++ 코어에 둡니다. 화면 개발을 위해 경제 규칙까지 다시 작성할 필요가 없도록 한 선택입니다.
대신 두 언어 사이의 계약을 관리해야 합니다. 같은 값을 UI 와 코어에서 따로 계산하면 표시와 실제 결과가 달라집니다. UI 는 코어가 돌려준 상태를 표시하고 명령 신호를 내보내며, 비용·가능 여부·거부 사유는 코어가 판정하도록 정했습니다. Godot 를 택했다는 사실만으로 이 경계가 자동으로 유지되지는 않습니다.
C++ GDExtension: 운영 규칙의 분리
GDExtension 은 엔진을 다시 컴파일하지 않고 네이티브 공유 라이브러리를 연결하는 방식입니다. 이 프로젝트는 C++20 코어를 godot-cpp 로 노출하고, Flecs 를 정적으로 연결합니다. 지형 생성·경로 탐색·의뢰 처리·경제·저장은 코어가 담당합니다. MSVC 환경을 불러오는 PowerShell 스크립트와 CMake·Ninja 로 debug·release DLL 을 구분해 빌드합니다.
선정 목적은 코어의 책임을 고정하고 처리 비용을 관리하는 것입니다. GDScript 버전과 같은 조건으로 비교한 실험은 없으므로 언어 선택 자체의 속도 향상률은 주장하지 않습니다. 함께 관리해야 할 제약도 있습니다. DLL 을 사용하는 게임이 실행 중이면 다시 링크할 수 없고, 배포 대상별 바이너리와 엔진 API 호환성을 관리해야 합니다. 현재 독립 실행 배포 경로는 Windows x86-64 를 대상으로 검증했습니다.
Flecs: 데이터 관리와 게임 규칙의 공존
ECS 는 객체를 식별하는 엔티티, 상태를 담는 컴포넌트, 해당 상태를 처리하는 시스템을 구분하는 구성 방식입니다. 실제 코드는 모험가·이동체·직원·가구와 길드·지도 상태를 Flecs 에 등록합니다. 이동은 등록된 시스템으로 처리하지만, 의뢰·주급·하루 정산은 명시적으로 순서를 정한 모듈 함수도 함께 사용합니다.
이 구성을 택한 이유는 데이터의 조회·수명 관리를 통일하면서 게임 규칙의 처리 순서를 파악하기 쉽게 하기 위해서입니다. 모든 규칙을 잘게 쪼갠 ECS 시스템으로 바꾼 구현은 아닙니다. 큰 상태 컴포넌트와 모듈 사이의 의존성은 여전히 관리 대상이며, Flecs 를 사용한다는 이유만으로 멀티스레드 실행이나 대규모 인원 처리가 검증된 것도 아닙니다.
HPA*: 건설로 바뀌는 지도에서의 길찾기
지도를 16 x 16 클러스터로 나누고 경계 입구·클러스터 내부 경로·층 연결을 관리합니다. 가까운 목적지는 국소 A* 로 처리하고, 긴 이동에는 계층형 탐색인 HPA* 를 사용하며, 필요하면 A* 로 대체합니다. 벽 모서리·문·계단·절벽 장비가 통행 조건이 되므로 단순한 평면 이동만으로는 충분하지 않았습니다.
이 방식에는 캐시 무효화와 복잡한 이동 규칙의 관리가 필요합니다. 건설이나 수리로 길이 바뀌면 통행 정보와 기존 경로를 갱신해야 합니다. 경로를 찾았는지뿐 아니라 실제 이동이 벽을 통과하지 않는지, 가구 이용 위치에 도달하는지, 계단과 절벽 장비의 조건이 맞는지도 따로 검증합니다. HPA* 를 넣었다는 사실만으로 모든 상황에서 최단 경로나 더 빠른 탐색을 보장하지는 않습니다.
JSON 정의 데이터와 자체 지형
시설·재료·직업·의뢰·밸런스·표시 이름은 JSON 정의 데이터로 관리하고 DefDatabase 가 읽습니다. 같은 정의를 코어의 계산과 UI 의 설명이 함께 사용하게 했습니다. 수치 변경을 코드 변경과 분리할 수 있지만, JSON 에서 새 키를 추가하는 것만으로 새로운 규칙이 작동하지는 않습니다. 필수 키·참조 대상·범위를 검증하고 이를 사용하는 코드를 함께 구현해야 합니다.
지형은 타일과 높이 데이터를 바탕으로 자체 청크 메시를 생성합니다. godot_voxel 은 적용하지 않았습니다. 지금 필요한 것은 해안 대륙·비탈·절벽·정해진 지하 층과 건설 부지이므로 이 규칙에 맞는 구현을 유지했습니다. 임의의 3D 복셀을 파내는 범용 지형 시스템으로 확장하려면 현재 표현과 통행 모델을 다시 검토해야 합니다.
업데이트 2까지의 지형·가구·캐릭터와 효과음은 코드로 생성하는 방식을 사용했습니다. 정의 값에서 형태를 바꾸고 필요한 변형을 만들기 쉽지만, 모델 연결부·외곽선·재질·음색의 품질을 직접 조정해야 합니다. 이후 별도 진행 중인 연출 이미지 제작까지 모두 같은 생성 방식이라고 일반화하지 않습니다.
고정 틱과 저장: 재현 범위의 구분
시뮬레이션은 20 TPS 고정 틱을 사용합니다. 시간 배속을 누적 시간에 적용하고, 한 프레임에서 처리하는 틱 수에 상한을 둡니다. 게임 규칙의 시간 단위를 화면 프레임과 분리하는 선택이지만, 과도한 부하에서 모든 경과 시간을 무제한 따라잡는 구조는 아닙니다.
지도 생성 시드는 고정할 수 있지만 판정·방문 난수는 비결정적입니다. 같은 지도 시드가 같은 운영 결과를 보장하지 않습니다. 저장도 모든 파생 캐시를 복사하는 방식이 아닙니다. JSON 에 운영 상태를 저장하고 경로·방 인식 같은 파생 정보를 다시 만듭니다. 새 시뮬레이션에 불러오기가 성공했을 때만 현재 게임을 교체합니다. 정확한 리플레이나 결정적 네트워크 동기화는 별도의 설계가 필요합니다.
실제 구현에서 확인한 판단 기준
아키텍처의 가치는 선택한 기술의 수보다 변경과 실패를 어디에서 다루는지에 있습니다. UI 는 계산을 복제하지 않고, 코어는 표시 노드에 의존하지 않으며, 정의 데이터와 저장 형식은 검증 경로를 갖도록 했습니다. 이후 최적화에서도 언어를 바꾸기보다 안개 재생성의 프레임 집중과 게시판 행 재생성을 먼저 줄였습니다. 남은 과제는 더 큰 지도·후반 인구에서의 부하 확인과 플랫폼별 배포 검증입니다.