Unity 로 게임을 몇 개 만들어 본 사람이라면 비슷한 벽을 만납니다. 작은 예제는 금방 만드는데, 조금만 커지면 코드가 엉킵니다. GameManager 가 모든 것을 알게 되고, 재시작할 때마다 무언가 하나씩 초기화가 빠지고, UI 를 고쳤더니 전투가 깨집니다. 기능 하나를 추가할 때 고쳐야 할 파일이 점점 늘어납니다.
이 책은 그 벽을 넘는 한 가지 방법을 게임 하나를 처음부터 끝까지 만들면서 보여 줍니다. Unity 공식 샘플 Zombie Toys 를 Game Framework 위에서 다시 조립합니다. 게임을 만드는 법보다는 게임이 커져도 엉키지 않게 만드는 법을 배우는 책입니다.
완성된 게임. 장난감 좀비들이 다섯 방향에서 몰려온다
이 책이 맞는 사람
•
MonoBehaviour, 프리팹, Rigidbody, 코루틴을 써서 작은 게임을 만들어 본 적이 있다
•
C# 의 클래스, 상속, 인터페이스를 읽을 수 있다
•
프레임워크는 처음이어도 된다
Unity 를 처음 배우는 분께는 어렵습니다. 기본 조작과 스크립팅을 익힌 뒤에 오세요.
무엇을 만드는가
위에서 내려다보는 서바이벌 슈터입니다. 방 한가운데서 사방에서 몰려오는 장난감 좀비들을 상대로 최대한 오래 버팁니다.
1.
두 캐릭터 중 하나를 클릭해 고른다
2.
WASD 로 움직이고 마우스로 조준한다
3.
무기 넷을 Tab 으로 바꿔 가며 쏜다 — 번개, 냉기, 악취, 슬라임
4.
적을 잡으면 점수가 오르고, 30점마다 숫자 1 로 양을 불러 적의 시선을 돌린다
5.
Esc 로 일시정지. 체력이 다하면 게임오버, R 로 다시 시작한다
입력 | 동작 |
마우스 클릭 | 캐릭터 선택 |
W A S D / 방향키 | 이동 |
마우스 이동 | 조준 (캐릭터가 커서 쪽을 본다) |
마우스 왼쪽 버튼 | 발사 (무기에 따라 누르는 동안 / 뗄 때) |
Tab | 무기 바꾸기 |
1 | 양 소환 |
Esc | 일시정지 메뉴 |
R | (게임오버 화면에서) 다시 시작 |
그림, 모델, 애니메이션, 소리는 Zombie Toys 의 것을 그대로 씁니다. 이 책에서 새로 쓰는 것은 코드입니다.
왜 프레임워크로 만드는가
원작 Zombie Toys 는 씬에 매니저 오브젝트들을 놓고 서로 직접 부르는 구조입니다. 예제로는 충분합니다. 다만 게임을 키우다 보면 같은 종류의 문제가 되풀이됩니다. 이 책에서는 그 자리를 프레임워크의 기능으로 하나씩 바꿉니다.
하고 싶은 일 | 흔한 방식 | 되풀이되는 문제 | 이 책의 방식 | 장 |
게임의 큰 흐름 | GameManager 의 bool 플래그 | 플래그 조합이 늘어나고, 재시작 때 초기화가 빠진다 | 프로시저 | 2, 9 |
캐릭터·적·총알 만들기 | Instantiate / Destroy | 끊김. 직접 만든 풀의 버그 | 엔티티 (풀이 기본) | 3–6 |
프리팹 가리키기 | 인스펙터에 드래그 | 씬이 모든 에셋을 물고 있다 | Addressables 주소 | 3 |
시스템끼리 알리기 | 싱글턴을 직접 호출 | 모두가 모두를 안다 | 이벤트 | 3, 7 |
캐릭터의 상황 구분 | Update 안의 if 사슬 | 상태가 늘 때마다 모든 분기를 다시 읽는다 | 상태 기계 (FSM) | 3–5 |
화면 UI | 씬에 놓은 Canvas 가 게임을 조회 | UI 를 고치면 게임이 깨진다 | UI 폼 • 이벤트 | 7 |
잠깐 쓰는 객체 | new | 초당 수십 번의 메모리 할당 | 참조 풀 | 3 |
효과음 | 오브젝트마다 AudioSource | 동시 재생 수와 볼륨을 통제하기 어렵다 | 사운드 그룹 | 8 |
프레임워크가 마법을 부리는 것은 아닙니다. 위의 문제들은 프레임워크 없이도 풀 수 있고, 실제로 많은 팀이 자기만의 방식으로 풉니다. 프레임워크는 그 풀이를 미리 만들어 두고, 지키기 쉽게 해 줄 뿐입니다. 그래서 이 책은 "이 함수를 부르면 된다"에서 멈추지 않고 왜 그렇게 생겼는지를 계속 설명합니다. 다른 프레임워크를 쓰게 되더라도 가져갈 수 있는 것은 그쪽입니다.
완성된 게임의 구조
끝까지 만들면 이런 모양이 됩니다. 지금은 눈에 익혀만 두고, 책을 다 읽은 뒤 다시 보세요.
graph TD
A["GameFramework 프리팹<br>(씬에 하나)"] --> B["프로시저"]
B --> C["ProcedureMain<br>한 판"]
C -->|"게임오버"| D["ProcedureGameOver<br>R 키 대기"]
D -->|"R"| C
C --> E["SurvivalGame<br>(평범한 C# 객체)"]
E --> S["EnemySpawner · AllySquad"]
E --> F["엔티티 띄우기"]
S --> F
F --> G["선택 캐릭터"]
F --> H["Player<br>+ 무기 넷"]
F --> I["Enemy 다섯 종"]
F --> J["투사체 · 이펙트 · 양"]
C --> K["UI 폼 열기"]
K --> L["HUDForm"]
K --> M["PauseMenuForm"]
H -.->|"이벤트"| L
I -.->|"이벤트"| E
E -.->|"이벤트"| LMermaid
복사
실선은 직접 부른다, 점선은 이벤트로 알린다입니다. 실선은 언제나 위에서 아래로만 내려가고, 아래에서 위로 가는 것은 전부 점선입니다. 점선으로 이어진 둘은 서로의 이름을 모릅니다. 이 한 가지 규칙이 책 전체에서 반복됩니다.
장 구성
장 | 만드는 것 | 새로 배우는 것 |
빈 방에서 프레임워크가 켜진다 | 프레임워크 프리팹, 필수 설정, 첫 프로시저 | |
"한 판"을 굴리는 뼈대 | 프로시저의 일생, 판마다 새로 만드는 게임 객체 | |
캐릭터 둘을 띄우고 클릭으로 고른다 | 엔티티, 주소, 주문서(EntityData), 참조 풀, 이벤트, 첫 FSM | |
걷고, 조준하고, 죽는 플레이어 | 같은 프리팹에 다른 로직, 체력의 공통 부모, 상태 셋 | |
쫓아와서 때리는 적 다섯 종 | 표로 정의하기, 스포너, "오는 중" 세기, NavMesh 와 풀 | |
성격이 다른 무기 넷 | 엔티티에 엔티티 붙이기, 공통 틀과 훅, 일회성 이펙트, 투사체, 상태 이상 | |
점수·체력·쿨다운 표시, 일시정지 메뉴 | UI 폼, 이벤트만 듣는 화면 | |
양 소환, 효과음·반복음·배경음악 | 기능을 얹는 비용 세어 보기, 사운드 그룹 | |
게임오버와 다시 시작 | 프로시저 전이, 풀 재사용 점검표 | |
스스로 넓혀 보기 | DataTable, Setting, Localization 으로 가는 길 |
장은 순서대로 읽어야 합니다. 뒤의 장은 앞 장에서 만든 파일을 고쳐 가며 진행합니다. 3장이 가장 새로운 것이 많고, 6장이 가장 깁니다. 3장을 넘기면 나머지는 같은 틀의 반복이라 점점 빨라집니다.
준비물
항목 | 내용 |
Unity | 6 (6000.6) · URP |
프레임워크 | 코어 Assets/Plugins/GameFramework.dll • Unity Game Framework Assets/Scripts/. Game Framework 를 Addressables 기반으로 고친 에디션이다. .unitypackage 하나로 들어온다 (1장) |
함께 쓰는 Unity 패키지 | Addressables, Input System, AI Navigation |
예제 프로젝트 | 완성된 게임 전체. 아트·프리팹·씬은 여기 것을 쓰고, Assets/GameMain 의 코드를 이 책을 따라 다시 쓴다 |
이 책은 씬에 가구를 배치하거나 UI 를 예쁘게 꾸미는 방법은 다루지 않습니다. 그런 것은 예제 프로젝트에 준비된 것을 쓰고, 각 장의 첫머리 "시작하기 전에 확인할 것" 에 그 장에서 필요한 준비물을 적어 두었습니다.
따라 하는 방법은 둘입니다.
•
처음부터 쓰기 (권장) — 예제 프로젝트를 복사한 뒤 Assets/GameMain 의 스크립트를 비우고, 1장부터 직접 써 나갑니다. 프리팹과 씬에 붙어 있던 스크립트 연결은 같은 이름·같은 네임스페이스로 다시 만들면 그대로 살아납니다(파일의 .meta 를 남겨 두는 것이 안전합니다).
•
읽으며 비교하기 — 완성된 프로젝트를 열어 두고, 각 장의 코드를 실제 파일과 나란히 놓고 읽습니다. 시간이 없을 때의 방법이지만, 손으로 쳐 봐야 남습니다.
이 책을 읽는 법
각 장은 같은 순서로 되어 있습니다.
부분 | 내용 |
도입 | 이 장에서 푸는 문제와, 끝났을 때의 화면 |
코드 | 파일 경로가 첫 줄에 적힌 코드. 예제 프로젝트의 실제 코드다 |
코드 읽기 | 방금 본 코드가 왜 그렇게 생겼는지. 이 책의 본문은 여기다 |
실행해 보기 | 지금까지 만든 것을 돌려 보고 확인할 것. 콘솔에 찍혀야 할 로그와 화면 |
잘 안 될 때 | 증상별 원인. 막히면 먼저 여기를 본다 |
이 장에서 만든 것 · 정리 | 파일 목록과, 다른 프로젝트에도 가져갈 수 있는 원칙 |
직접 해 보기 | 값을 바꿔 보거나, 일부러 줄을 지워 무엇이 깨지는지 보는 실험 |
코드를 읽을 때 알아 둘 약속입니다.
•
책의 코드는 주석을 줄였습니다. 예제 프로젝트의 파일에는 "왜 이렇게 했는가"가 훨씬 길게 적혀 있습니다. 따라 친 뒤 원본도 열어 보세요.
•
파일 전체를 싣지 않고 고칠 부분만 보일 때가 있습니다. 그때는 "어느 메서드의 어디에" 넣는지를 글로 적었습니다.
•
// 확인용 이라고 적힌 줄은 동작을 눈으로 보려고 잠깐 넣는 코드입니다. 확인한 뒤 지웁니다.
•
앞 장에서 단순하게 만든 것을 뒤 장에서 바꾸는 일이 있습니다. 그때는 "3.9 절에서 바꾼다"처럼 미리 적어 두었습니다.
•
"직접 해 보기"에서 일부러 깨뜨린 코드는 반드시 되돌려 놓고 다음으로 넘어가세요.
코드 스타일
이 책의 코드는 몇 가지 규칙을 일관되게 따릅니다.
private float mGameTime = 0f; // 필드는 m 으로 시작한다
private const float HideDelayAfterDeath = 1.5f; // 숫자에는 이름을 붙인다
if (GameOver) return; // 본문이 "빠져나가기" 한 줄이면 중괄호 없이 한 줄
if (selected != null) // 그 밖에는 한 줄이어도 중괄호를 쓴다
{
selected.SafeHide();
}
bool isPlayerInAttackRange = distance <= range; // 조건에 이름을 붙여 읽히게 한다
if (!isPlayerInAttackRange) return;
C#
복사
메서드는 대개 안 되는 경우를 위에서 먼저 돌려보내고, 맨 아래에 정작 하려던 일이 한 번 나옵니다. 처음에는 낯설 수 있지만 몇 장 읽다 보면 "아래로 갈수록 조건이 좁혀진다"는 흐름이 눈에 들어옵니다.
폴더 구조
Assets/Plugins/GameFramework.dll ← 프레임워크의 코어. 엔진과 무관한 핵심. 별도 C# 프로젝트로 빌드한 DLL 이다
Assets/Scripts/ ← Unity Game Framework. 코어를 Unity 와 잇는 부분 — 컴포넌트, EntityLogic, UIFormLogic
Editor/ 전용 인스펙터와 Game Framework 메뉴
(위 둘은 이 책에서 고치지 않는다)
Assets/GameMain/ ← 이 책에서 쓰는 코드는 전부 여기
Procdure/ 프로시저 (ProcedureMain, ProcedureGameOver)
Game/ 게임 객체, 스포너, 표, 이벤트 인자
Entity/
EntityData/ 주문서 (PlayerData, EnemyData …)
EntityLogic/ 엔티티의 동작 (Player, Enemy …)
States/ 상태 클래스
Weapon/ 무기 묶음, 무기의 공통 틀, 무기 넷
UI/ UI 폼 (HUDForm, PauseMenuForm)과 프리팹
Camera/ 카메라(프레임워크 컴포넌트), 선택 화면 조명(엔티티)
Utility/ 작은 도구들
Plain Text
복사
폴더 이름 Procdure 는 오타가 아니라… 오타가 맞습니다. 예제 프로젝트에 그렇게 되어 있어서 책도 그대로 적습니다. 네임스페이스는 전부 ToyBoxNightmare 입니다.
자주 나오는 말
말 | 뜻 | 처음 나오는 곳 |
프로시저 | 게임의 큰 단계 하나. 한 번에 하나만 실행된다 | 1·2장 |
게임 객체 | "한 판"의 규칙을 담은 평범한 C# 객체 (SurvivalGame). Unity 의 GameObject 와 다른 말이다 | 2장 |
엔티티 | 게임 도중 나타났다 사라지는 것. 풀에서 재사용된다 | 3장 |
로직 | 엔티티나 UI 폼의 동작을 적은 스크립트 (EntityLogic, UIFormLogic) | 3장 |
주문서 | 이 책에서 EntityData 를 부르는 말. 스폰을 요청할 때 적고, 나타날 때 읽는다 | 3장 |
주소 | Addressables 에 등록한 에셋의 이름. "Girl" | 3장 |
풀 | 사라진 엔티티·UI 폼 인스턴스를 부수지 않고 모아 두는 곳 | 3장 |
참조 풀 | 주문서나 이벤트 인자 같은 작은 C# 객체를 모아 두는 곳. 위의 풀과 다르다 | 3장 |
이벤트 / 핸들러 | "무슨 일이 일어났다"는 알림 / 그 알림을 받았을 때 불리는 메서드 | 3장 |
상태 기계 (FSM) | "지금 무엇을 하는 중인가"를 클래스 하나씩으로 나눈 것 | 3장 |
훅 | 부모가 정해진 때에 불러 주는, 자식이 채우는 빈 메서드 (OnDamaged, OnFireHeld …) | 4장 |
UI 폼 | 화면 하나. HUD, 메뉴 | 7장 |




