본문으로 건너뛰기
게임 프로젝트 기초집LESSON 20

최종 실습: 2D 택배 분류 게임 출시 후보 완성하기

난이도초급 프로젝트
예상 시간120분
선수지식1~19강 결과물

20강. 최종 실습: 2D 택배 분류 게임 출시 후보 완성하기

1. 이번 강의에서 해결할 문제​

기능이 각각 동작해도 시작부터 재시작까지 연결되고 긴 플레이와 잘못된 설정을 견뎌야 출시 후보가 됩니다. 전체 구조와 증거 문서를 하나의 완료 기준으로 묶습니다.

2. 학습 목표​

3. 핵심 개념​

최종 책임 흐름은 다음과 같습니다.

GameFlow ─상태─> Spawner / Input ─명령─> PackageActor
│ │
Difficulty + Selector ─데이터─────┘ Trigger 결과 1회
│
GameSession ─이벤트─> HUD / Audio / HighScoreStore
│
GameRules + PackageDefinition

GameFlow는 시스템 활성화, GameSession은 점수·목숨, Spawner는 생성 시점, Selector는 종류 순서, PackageActor는 이동·중복 차단, Presenter는 표시·사운드를 맡습니다.

핵심 Unity API와 책임 경계​

API·기능호출 주체구체 결과주의할 점
Awake각 ComponentInspector 필수 참조와 값 범위를 첫 실행 전에 검증오류를 기록한 뒤 잘못된 시스템 시작을 막습니다.
StartCoroutine·WaitForSecondsSpawner택배 생성과 다음 생성 사이의 대기 순서를 표현중복 Coroutine과 Time Scale 정책을 확인합니다.
OnTriggerEnter2DZonePackageActor의 분류·놓침 결과를 1회 요청Collider·Rigidbody2D 설정과 TryResolve가 필요합니다.
C# eventGameSession 발행, Presenter 구독점수·목숨 변경이 HUD·Audio에 전달OnEnable·OnDisable 구독 대칭을 유지합니다.
Time.timeScaleGameFlowscaled 이동·대기를 일시정지UI 입력과 unscaled 동작은 별도로 제어합니다.
PlayerPrefsHighScoreStore비민감 최고 점수를 로컬에 유지인증·결제·개인정보를 저장하지 않습니다.
SceneManager.LoadSceneGameFlowScene 소유 런타임 객체를 새로 생성Build Scene 등록과 Time Scale 복원을 확인합니다.

출시 후보에서는 “한 클래스가 모든 API를 호출한다”보다 API 결과가 어느 책임으로 전달되는지가 중요합니다. 물리 Trigger는 PackageActor의 한 번 처리 계약을 거쳐 GameSession에 도달하고, 점수 이벤트는 Presenter로만 나갑니다.

4. 단계별 실습​

시작 전 상태​

  • 1~19강 결과가 같은 Unity 버전에서 컴파일되고 Main Scene을 Play할 수 있어야 합니다.
  • Console 오류 0개, 현재 Git 상태와 ProjectVersion을 기록합니다.
  • 최종 Scene과 Prefab을 복사해 새 구조로 다시 만들지 말고 기존 결과물의 책임과 참조를 점검합니다.
  • 모든 기능을 동시에 켜기 전에 아래 출시 후보 게이트를 순서대로 닫습니다.

작은 수직 조각과 출시 후보 게이트​

게이트통합 범위통과 증거
0Main Scene + GameFlow + GameSessionStart 버튼 뒤 Playing, 점수 0, 목숨 기본값
1PackageDefinition + Pool + PackageActor 한 개한 종류가 생성·이동하고 올바른 Zone에서 결과 1회
2Selector + 두 종류 + 오분류·놓침실제 Type과 Zone Type에 따라 점수·목숨이 손 계산과 일치
3Pause·GameOver·Restart입력·생성·Time Scale·Panel이 상태표와 일치
4Difficulty + 연속 제한 + 빠른 생성최소 간격과 4회째 강제 변경, Pool 상태 초기화 확인
5HUD·Audio·HighScore이벤트 1회당 표시·소리 1회, 재시작 뒤 최고 점수 유지
615분 플레이 + 독립 빌드지속 증가 없음, 시작부터 재시작까지 완료

각 게이트의 실패는 재현 입력 → 기대값 → 실제값 → 첫 불일치 책임 순서로 기록합니다. Gate 1이 실패한 상태에서 Difficulty와 Audio까지 켜지 않습니다.

4-1. 최종 프로젝트 구조​

Assets/_Project/
├─ Art/ # 직접 제작 또는 라이선스 확인 에셋
├─ Audio/
├─ Data/ # GameRules, Difficulty, PackageDefinition
├─ Docs/ # 기획, 테스트, 알려진 문제, 포트폴리오
├─ Prefabs/Package.prefab
├─ Scenes/Main.unity
└─ Scripts/
├─ Core/ # GameSession, GameFlow, HighScoreStore
├─ Data/ # ScriptableObject 타입
├─ Gameplay/ # Spawner, Selector, Actor, Zone, Pool, Input
├─ UI/HudPresenter.cs
└─ Audio/AudioPresenter.cs

4-2. Inspector 연결 점검​

Unity Editor·Inspector 작업

  1. Package Prefab에 SpriteRenderer, Collider2D, Rigidbody2D와 PackageActor를 연결합니다.
  2. Pool에 Prefab, Spawner에 Pool·SpawnPoint·Bounds·Difficulty·Selector를 연결합니다.
  3. Blue·Orange Zone에 각각 올바른 PackageDefinition을 연결합니다.
  4. Session에 GameRules, Flow에 Session·Spawner·Input·HighScoreStore를 연결합니다.
  5. HUD와 Audio Presenter의 이벤트 발행자·표시·클립 참조를 연결합니다.

필수 참조는 각 컴포넌트의 Awake에서 이름이 포함된 오류로 검증하고, null이면 해당 시스템 시작을 막습니다. Find 계열을 Update에서 호출하지 않습니다.

4-3. 구조 선택 근거​

문서 · 파일 경로: Assets/_Project/Docs/Architecture.md

Architecture.md
# 구조 선택 근거
- Update: 현재 택배의 연속 이동과 입력 읽기에만 사용한다.
- Coroutine: 택배 생성과 간격 대기를 순서대로 표현한다.
- Object Pool: 빠르게 반복되는 동일 Prefab의 생성·제거를 재사용한다.
- ScriptableObject: 택배·게임·난이도 설계 수치를 인스턴스와 분리한다.
- event: GameSession이 HUD와 Audio 구현을 모르게 한다.

4-4. 최종 테스트​

문서 · 파일 경로: Assets/_Project/Docs/FinalTest.md

FinalTest.md
# 최종 테스트
- [ ] 시작 → 플레이 → 일시정지 → 재개 → 게임 오버 → 재시작
- [ ] 두 종류 이상과 대응 Zone, 정답 점수 증가
- [ ] 오분류·놓침에서 목숨 정확히 1 감소
- [ ] 점수·최고 점수·목숨·상태 UI 일치
- [ ] 3회 연속 허용, 4회째 다른 종류
- [ ] 시간 경과에 따른 간격·속도 변화와 최소값
- [ ] 0.1초 빠른 생성에서 Pool·중복 판정 오류 없음
- [ ] 택배가 없는 상황에서 오류 없음
- [ ] 목숨 0에서 입력·추가 생성 중단
- [ ] Inspector 연결 누락에서 구체적 오류
- [ ] 15분 플레이에서 메모리·비활성 객체·구독의 지속 증가 없음

4-4-1. 손으로 검산할 기준 시나리오​

GameRules가 정답 +100점, 오분류·놓침 목숨 -1, 시작 목숨 3이라고 가정합니다. 실제 에셋 값이 다르면 표 숫자를 먼저 프로젝트 값으로 바꿉니다.

순서행동기대 점수기대 목숨기대 상태
1Blue → BlueZone1003Playing
2Orange → BlueZone1002Playing
3Blue → MissZone1001Playing
4Orange → MissZone1000GameOver
5Restart03Start 또는 프로젝트의 시작 대기 상태

Trigger가 겹치더라도 한 Package는 표의 한 행만 진행해야 합니다. HUD와 Audio는 GameSession의 같은 이벤트를 관찰하므로 실제 점수·목숨과 한 프레임 이상 어긋난 상태가 계속되면 구독 또는 초기 표시를 확인합니다.

4-5. 빌드 전과 알려진 문제​

ReleaseChecklist.md에 Scene, 해상도, 아이콘, 저작권, 입력, Console과 독립 빌드 결과를 기록합니다. KnownIssues.md에는 재현 절차, 영향, 임시 대응과 다음 수정 항목을 작성합니다.

4-6. 포트폴리오 기록​

문서 · 파일 경로: Assets/_Project/Docs/Portfolio.md

Portfolio.md
# Delivery Sorter Release

## 게임 소개
색과 아이콘을 빠르게 읽어 떨어지는 택배를 올바른 지점으로 보내는 2D 액션 게임입니다.

## 맡은 기능
게임 상태, 데이터 기반 난이도, 연속 생성 제한, 판정 이벤트, HUD, Pool과 로컬 최고 점수

## 기술적 문제 해결
겹친 Trigger의 중복 점수를 PackageActor.TryResolve로 한 번만 허용하고 재현 테스트를 추가했습니다.

## 핵심 재미와 현재 한계
- 재미: 짧은 판단과 즉시 피드백, 점차 빨라지는 압박
- 한계: 키보드 중심 입력, 2종 콘텐츠, 로컬 기록만 지원
- 다음 개선: 실제 기기 터치, 프로파일링, 튜토리얼·추가 택배

4-7. 최종 파일 확인​

PowerShell · 실행 위치: 프로젝트 루트

Get-ChildItem .\Assets\_Project\Scripts -Recurse -Filter *.cs
Get-ChildItem .\Assets\_Project\Docs -Filter *.md
Get-Content .\ProjectSettings\ProjectVersion.txt
git status --short

예상 결과: 책임별 코드와 기획·테스트·출시·포트폴리오 문서, 정확한 Unity 버전이 보입니다. C# 컴파일과 Play Mode·빌드 검증은 Unity Editor와 독립 실행 파일에서 수행합니다.

4-8. 이후 확장 아이디어​

  • 모바일 입력: Input System Touch Action, 드래그 어댑터, Safe Area와 진동 피드백
  • 성능 최적화: 실제 기기 Profiler, Sprite Atlas, 목표 FPS·메모리 예산
  • 광고: 실제 SDK는 추가하지 않고 게임 규칙과 Adapter 경계, 테스트 광고·개인정보 정책을 먼저 설계
  • 스토어 출시: 아이콘·스크린샷·서명 키·등급·개인정보와 현재 스토어 정책 점검

5. 코드가 동작하는 이유​

설계 데이터와 런타임 상태, 생성과 판정, UI와 오디오가 이벤트 경계로 연결됩니다. 한 시스템을 바꾸어도 다른 책임의 내부 코드를 덜 수정하며, 상태 전환이 입력·생성·화면을 일관되게 조정합니다.

6. 자주 하는 실수와 해결법​

7. 직접 실습​

따라 하기: 출시 후보 기준선 만들기​

Gate 0~3만 켠 상태로 위 기준 시나리오를 실행합니다. 각 행마다 GameSession 값, HUD 텍스트, 활성 Panel, Spawner·Input 상태를 기록합니다. 네 행이 통과하기 전에는 난이도나 새 콘텐츠를 추가하지 않습니다.

값과 실패 바꿔 보기​

  1. Difficulty의 최소 생성 간격을 0.1초로 낮춰 Pool 부족, 중복 판정, Frame Spike를 재현하고 Profiler 캡처를 남깁니다.
  2. Session·Pool·TMP·AudioClip 참조를 하나씩 비워 Awake가 구체적인 필드·오브젝트 이름을 보고하는지 확인합니다.
  3. BlueZone과 MissZone을 겹쳐 PackageActor의 TryResolve가 첫 결과만 허용하는지 검사합니다.
  4. Pause 직후 GameOver와 Restart를 반복해 Time Scale, 이벤트 구독과 비활성 Pool 개수가 누적되지 않는지 확인합니다.

직접 확장​

출시 후보 기준선과 독립 빌드가 통과한 별도 브랜치에서만 세 번째 PackageDefinition과 Zone을 추가합니다. Selector 목록·데이터·Inspector 연결만 바꾸고 GameSession과 Presenter에 종류별 분기를 추가하지 않는 것을 목표로 합니다. 확장 후 Gate 1~6을 다시 실행해 회귀 결과를 남깁니다.

스스로 확인​

막혔을 때​

증상첫 확인 책임해결 방향
Start 뒤 아무 Package도 안 나옴GameFlow → Spawner → Pool상태 로그, Coroutine Handle, Pool Prefab과 SpawnPoint 순으로 확인합니다.
점수·HUD·소리가 서로 다름GameSession event → Presenter규칙 원본 값과 구독 수를 기록하고 Presenter가 값을 재계산하지 않게 합니다.
재시작할수록 Callback 증가OnEnable·OnDisable 또는 DontDestroyOnLoad 중복구독 해제와 Scene에 남는 전역 객체 수를 확인합니다.
Editor에서는 되지만 독립 빌드 실패Build Scene·플랫폼 설정·대소문자 경로Player.log와 ReleaseChecklist의 첫 오류부터 수정합니다.
긴 플레이에서 메모리 계속 증가Pool 반환·이벤트·로그·에셋 할당Profiler Timeline과 Memory 비교로 증가 주체를 특정합니다.

모든 통과와 실패를 기록한 뒤 핵심 재미, 한계, 다음 개선, 맡은 기능과 기술적 문제 해결 경험을 완성합니다.

8. 이해 점검 질문 3개​

9. 핵심 요약​

MINI QUIZ

최종 실습: 2D 택배 분류 게임 출시 후보 완성하기 미니 퀴즈

선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.

0 / 2
  1. 문제 1“최종 실습: 2D 택배 분류 게임 출시 후보 완성하기” 구현을 설계할 때 책임과 구조를 올바르게 나눈 선택은 무엇인가요?
  2. 문제 2“최종 실습: 2D 택배 분류 게임 출시 후보 완성하기”에서 ‘Pool 상태 초기화 누락’ 문제가 생겼습니다. 가장 알맞은 진단 또는 대응은 무엇인가요?
LESSON STATUS

학습을 마쳤나요?

직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.

20강. 최종 실습: 2D 택배 분류 게임 출시 후보 완성하기 미완료 상태