최종 실습: 2D 택배 분류 게임
24강. 최종 실습: 2D 택배 분류 게임
1. 이번 강의에서 해결할 문제
각 기능은 따로 동작하지만 택배 생성부터 분류, 점수·목숨, 게임 오버와 결과 화면까지 하나의 플레이 흐름으로 연결하고 경계 상황을 검증해야 합니다.
2. 학습 목표
3. 핵심 개념
최종 구조는 한 거대한 GameManager가 아니라 다음 흐름으로 연결됩니다.
PackageSpawner --Get--> PackagePool --Activate--> PackageItem
│ │
└─ PackageTypeSelector └─ Trigger 도착
│
SortZone / MissZone ──결과 요청──> GameSession ──event──> HUD / Feedback / SceneFlow
- Inspector: Prefab, 데이터 에셋, Zone 위치, 기본 수치 연결
- C#: 생성 제한, 이동, 판정, 점수·목숨과 상태 전환
- 이벤트: GameSession과 UI·피드백의 결합 제거
- 멀티플레이, 서버 저장, 광고 SDK는 이 과정 범위 밖입니다.
4. 단계별 실습
4-1. 최종 폴더와 Scene 구성
Assets/DeliverySorter/
├─ Data/PackageTypes/{Blue,Orange}.asset
├─ Prefabs/Package.prefab
├─ Scenes/{Game,Result}.unity
└─ Scripts/
├─ Data/PackageTypeData.cs
├─ Packages/{PackageItem,PackageMotor2D}.cs
├─ Spawning/{PackagePool,PackageSpawner,PackageTypeSelector}.cs
├─ Zones/{SortZone,MissZone}.cs
├─ Game/{GameSession,SceneFlow}.cs
├─ UI/HUDPresenter.cs
└─ Feedback/SortFeedback.cs
Unity Editor·Inspector 작업
- Package Prefab에 SpriteRenderer, Rigidbody2D, BoxCollider2D, PackageItem과 PackageMotor2D를 둡니다.
- Rigidbody2D는 Dynamic, Gravity Scale 0, Freeze Rotation Z로 설정합니다.
- BlueZone·OrangeZone·MissZone의 Collider2D는 Is Trigger로 둡니다.
- PackagePool에 Prefab, PackageSpawner에 Pool·SpawnPoint·두 데이터 에셋을 연결합니다.
- GameSession과 HUDPresenter, SortFeedback 참조를 연결합니다.
4-2. 최종 분류와 놓침 판정
C# · 파일 경로: Assets/DeliverySorter/Scripts/Zones/SortZone.cs
using UnityEngine;
public sealed class SortZone : MonoBehaviour
{
[SerializeField] private PackageTypeData acceptedType;
[SerializeField] private GameSession session;
private void Awake()
{
if (acceptedType == null || session == null)
Debug.LogError("SortZone reference is missing.", this);
}
private void OnTriggerEnter2D(Collider2D other)
{
if (!other.TryGetComponent(out PackageItem package)) return;
if (package.IsResolved || package.Type == null) return;
session.RegisterSort(package.Type, acceptedType);
package.ResolveAndRelease();
}
}
C# · 파일 경로: Assets/DeliverySorter/Scripts/Zones/MissZone.cs
using UnityEngine;
public sealed class MissZone : MonoBehaviour
{
[SerializeField] private GameSession session;
private void OnTriggerEnter2D(Collider2D other)
{
if (!other.TryGetComponent(out PackageItem package)) return;
if (package.IsResolved) return;
session.RegisterFailure();
package.ResolveAndRelease();
}
}
4-3. 최종 생성 루프
C# · 파일 경로: Assets/DeliverySorter/Scripts/Spawning/PackageSpawner.cs
using System.Collections;
using UnityEngine;
public sealed class PackageSpawner : MonoBehaviour
{
[SerializeField] private PackagePool pool;
[SerializeField] private Transform spawnPoint;
[SerializeField] private PackageTypeSelector selector;
[SerializeField, Min(0.1f)] private float startInterval = 1.5f;
[SerializeField, Min(0.1f)] private float minInterval = 0.45f;
private Coroutine routine;
private float startedAt;
public void StartRun()
{
if (routine != null) return;
startedAt = Time.time;
routine = StartCoroutine(SpawnLoop());
}
public void StopRun()
{
if (routine == null) return;
StopCoroutine(routine);
routine = null;
}
private IEnumerator SpawnLoop()
{
while (true)
{
PackageTypeData type = selector.Next();
if (type != null) pool.Get(type, spawnPoint.position);
float minutes = (Time.time - startedAt) / 60f;
float interval = Mathf.Max(minInterval, startInterval - minutes * 0.2f);
yield return new WaitForSeconds(interval);
}
}
}
StateChanged를 구독하는 Binder가 Playing에서 StartRun, Paused·GameOver에서 StopRun을 호출합니다. GameOver에서는 입력도 비활성화하고 최고 점수를 저장한 뒤 결과 화면 버튼을 제공합니다.
4-4. 실행
PowerShell · 실행 위치: DeliverySorter2D 프로젝트 루트
Get-ChildItem .\Assets\DeliverySorter\Scripts -Recurse -Filter *.cs
Get-Content .\ProjectSettings\ProjectVersion.txt
Unity Editor에서 Console을 비우고 Game Scene을 Play합니다. C# 컴파일과 실제 Play Mode 검증은 반드시 에디터에서 수행합니다.
5. 코드가 동작하는 이유
Spawner는 Coroutine으로 생성 시점만 관리하고 selector가 실제 타입을 결정해 같은 종류가 최대 세 번까지만 이어집니다. Pool은 인스턴스를 재사용하고 PackageItem은 한 번만 해결됩니다. Zone은 결과만 GameSession에 전달하며, GameSession 이벤트를 HUD와 피드백이 구독하므로 UI가 점수 규칙에 섞이지 않습니다.
구조 선택 근거
| 구조 | 선택 이유 |
|---|---|
| Update·FixedUpdate | 입력은 프레임, Rigidbody2D 이동은 물리 주기마다 필요 |
| Coroutine | 생성 간격과 난이도 대기를 순서대로 표현 |
| Object Pool | 빠르게 반복되는 택배 생성·제거 비용과 GC 할당 완화 |
| ScriptableObject | 타입별 색상·점수를 Prefab 복제 없이 공유 |
| event | 게임 규칙이 HUD와 사운드의 구체 구현을 모르게 함 |
6. 자주 하는 실수와 해결법
7. 직접 실습
8. 이해 점검 질문 3개
9. 핵심 요약
최종 실습: 2D 택배 분류 게임 미니 퀴즈
선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.
학습을 마쳤나요?
직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.