
Tiny Reign을 만들면서 유닛 수가 늘어날수록 한 가지가 계속 신경 쓰였다. 스탯이 코드에 박혀 있다는 것. 전사 공격력을 바꾸려면 .gd 파일을 열고 숫자를 찾아서 고쳐야 했다. 유닛이 네 종류일 때도 이미 귀찮았는데, 앞으로 더 늘어나면 어떻게 하나 싶었다.
CSV 하나로 시작했다
unit_stats.csv 파일 하나에 유닛 종류별로 행을 나눴다. 열은 unit_type, hp, atk, speed, detection_range, attack_range, attack_cooldown 같은 식이다. 이걸 Autoload 싱글턴인 UnitStatsDB에서 게임 시작할 때 한 번 읽어서 딕셔너리로 들고 있는다.
실제로 유닛이 스탯을 가져올 때는 UnitStatsDB.get_stats(“warrior”) 한 줄이면 된다. CSV 파싱도 Godot의 FileAccess로 충분했다. 복잡한 라이브러리 없이도 됐다.
써보니 좋았던 것들
가장 좋은 건 밸런싱이 쉬워졌다는 거다. 전사 체력이 너무 강하다 싶으면 CSV 열어서 숫자 바꾸고 저장하면 끝이다. 코드를 건드릴 필요가 없으니 실수도 줄었다.
AI 협업할 때도 편했다. “warrior의 attack_range를 155로 바꿔줘”라고 하면 AI가 CSV를 직접 수정해준다. 코드 구조를 설명할 필요가 없다. 숫자가 어디 있는지 명확하니까.
Red팀 유닛을 추가할 때도 Blue팀 CSV를 복사해서 수치만 조금 바꿨다. 행 하나 추가하는 게 전부였다.
주의할 점
CSV는 타입 정보가 없다. 파싱할 때 int()나 float()로 직접 변환해야 한다. 이걸 빠뜨리면 숫자인데 문자열로 들어와서 비교가 안 되는 버그가 생긴다. 처음에 이걸 몰라서 공격 판정이 왜 안 되는지 한참 헤맸다.
열 순서가 바뀌면 파서가 깨질 수 있으니 헤더 이름 기반으로 읽는 게 안전하다. Godot에서 CSV 첫 줄을 키로 쓰는 방식으로 구현하면 나중에 열을 추가해도 기존 코드가 안 깨진다.
발사체 데이터도 같은 방식으로 ProjectileStatsDB를 따로 만들었다. 화살 속도, 데미지, 관통 횟수 같은 것들. 데이터 파일이 분리되어 있으니 나중에 찾기도 쉬웠다.
정리하자면
데이터 주도 설계(data-driven)라는 거창한 말이 있는데, CSV 파일 하나가 그 출발점이 될 수 있다. 하드코딩 제거, 밸런싱 편의, AI 협업 모두에서 효과를 봤다. 규모가 커지면 JSON이나 DB로 교체하기도 어렵지 않다. 게임 스탯을 아직 코드에 박아두고 있다면 CSV부터 시작해보는 걸 추천한다.






