Unity 공식 Survival Shooter의 플레이 영상과 리소스만 참고해 게임플레이를 처음부터 설계하고 구현한 탑다운 서바이벌 슈터입니다. 개발 당시에는 원본 소스와 프로젝트 구조를 보지 않았습니다. 2023년에 완성한 뒤 Unity 6와 URP 환경으로 옮기면서 프로젝트 구조를 재정비했습니다. 공식 샘플 원본은 현재 비교와 참고용으로 별도 보관합니다.
이미지를 누르면 YouTube 플레이 영상으로 이동합니다.
왼쪽 위부터 시계 방향으로 스테이지 시작 전 조작 안내, 몬스터 교전과 피해량 표시, 게임 오버 후 재시작, 몬스터에 포위된 상황입니다.
플레이어는 탑다운 시점에서 몰려오는 몬스터를 사격으로 처치하며 생존합니다. 몬스터는 일정 간격으로 스폰되어 NavMesh로 플레이어를 추적하고, 처치할수록 점수가 오릅니다. 플레이어 체력이 0이 되면 게임이 끝나고, 재시작 버튼을 누르면 몬스터와 점수, 플레이어 위치가 모두 초기 상태로 돌아갑니다.
| 동작 | 입력 |
|---|---|
| 이동 | WASD |
| 조준 | 마우스 이동 (바닥 레이캐스트 지점을 바라봄) |
| 사격 | 마우스 왼쪽 버튼 (히트스캔 + LineRenderer) |
- 빌트인 파이프라인으로 만든 프로젝트를 Unity 6000.3.18f1과 URP 17.3.0으로 이식
- 게임플레이 스크립트를
SurvivalShooter2023.asmdef로 격리하고 공식 샘플 원본을OriginalSurvivalShooter어셈블리로 분리해 동명 클래스 충돌 해소 - URP에서 깨지는 빌트인 머티리얼을 URP 셰이더로 전환
- 커스텀 레벨 Environment를 새 GUID로 승격해 공유 아트를 참조하면서 오버라이드 보존
- Cinemachine 2 카메라를 Cinemachine 3으로 재구성
- 종료 시 싱글톤 접근 경고를
_isQuitting가드로 차단
- 공식 샘플의 플레이 영상과 리소스만 참고해 게임플레이를 설계하고 구현
- 이벤트로 상태를 공유하고 행동을 단일 책임 컴포넌트로 나누는 구조 설계
SurvivalShooter/Assets/
├── _SurvivalShooter2023/ # 직접 작성한 게임 본체
│ ├── 00_Scenes/ # GameScene과 베이크된 NavMesh
│ ├── 01_Scripts/ # SurvivalShooter2023.asmdef로 격리된 게임플레이 어셈블리
│ │ ├── Common/ # GameManager, Singleton, MonsterSpawn, UI 매니저, Validate
│ │ ├── Entity/ # Entity 베이스와 Player/Monster, Movement/Attack/Animation/Sound
│ │ └── UI/ # 애니메이션 클립에서 호출하는 UI 로직
│ ├── 02_Prefabs/ # Characters, Maps, Particle
│ ├── 03_UI/ # 월드 공간 UI 프리팹
│ └── 04_Art/ # Animation, AudioClips, Fonts, Images, Materials, Models
│
├── ThirdParty/
│ └── OriginalSurvivalShooter/ # Unity 공식 Survival Shooter 샘플 (참조 및 공유 아트)
├── Settings/ # URP 렌더 파이프라인 에셋
└── TextMesh Pro/ # TMP essentials
게임플레이 코드는 SurvivalShooter2023.asmdef로 별도 어셈블리에 격리합니다. 컴파일 경계를 분명히 하고, 참조 아카이브(OriginalSurvivalShooter)의 동명 클래스와 충돌하지 않게 하려는 목적입니다.
설계 원칙은 "실수하기 어려운 구조"입니다. 책임을 작은 컴포넌트로 나누고, 이벤트로 느슨하게 연결하며, 인스펙터 단계에서 누락을 잡습니다.
GameManager는 Singleton<T>를 상속한 중앙 상태 허브입니다. 진행 상태(IsPlaying, IsStageStarted)와 점수(GameScore)를 들고, 프로퍼티에 값을 대입할 때 C# 이벤트(OnGameStarted, OnStageStarted, OnGameScoreChanged)를 발행합니다. UI와 사운드, 스폰은 이 이벤트를 구독해 동작하므로 서로를 직접 참조하지 않습니다.
Singleton<T>는 종료 중 접근을 막는 _isQuitting 가드를 둡니다. OnApplicationQuit이 모든 OnDestroy보다 먼저 호출되는 순서를 이용해, 파괴 순서 때문에 생기는 거짓 경고를 베이스 한 곳에서 차단합니다.
Entity 추상 클래스가 체력과 상태 이벤트(OnDeath, OnHpChanged, OnAttacked, OnMoveStateChanged)를 정의하고, Player와 Monster가 이를 상속합니다. 행동은 단일 책임 컴포넌트로 나눕니다.
- Player:
Player+PlayerMovement(이동과 조준) +PlayerAttack(히트스캔 사격) +EntityAnimationController+EntitySoundplayer - Monster:
Monster+MonsterMovement(NavMeshAgent 추적) +MonsterAttack(트리거 접촉 시 반복 공격) +MonsterUIManager(체력바와 피해량 표시) +EntityAnimationController+EntitySoundplayer
전투는 옵저버 패턴으로 흐릅니다. PlayerAttack이 레이캐스트로 대상을 찾아 Entity.ExecuteAttack을 호출하면 OnAttacked 이벤트가 발행되고, 데미지 적용과 총구 파티클, 피격 파티클은 PlayerAttack이 같은 이벤트를 구독해 처리합니다. EntityAnimationController와 EntitySoundplayer도 이 이벤트를 구독하므로, 애니메이션과 사운드는 공격 코드를 고치지 않고 붙이거나 뗄 수 있습니다.
MonsterSpawn은 스테이지 시작 이벤트를 받아 코루틴으로 몬스터를 생성합니다. 쥐구멍과 바닥 두 경로로 확률 분기하며, 바닥 스폰 지점은 위에서 아래로 쏜 SphereCast에 바닥 말고 다른 콜라이더가 걸리지 않으면서 카메라 화면 밖인 곳만 고릅니다. 몬스터가 장애물에 끼거나 화면 안에서 갑자기 나타나는 것을 막으려는 처리입니다.
스테이지는 플레이어의 첫 이동이나 첫 사격에서 시작합니다. 재시작하면 같은 조건을 다시 기다리므로, 조작 안내를 읽고 나서 시작할 수 있습니다.
필수 참조를 받는 컴포넌트는 OnValidate에서 Validate.NullCheck를 호출해, 직렬화 필드가 비면 에디터에서 바로 경고합니다. 리플렉션으로 필드와 프로퍼티를 모두 찾으므로 [field: SerializeField] 자동 구현 프로퍼티에도 걸립니다. 플레이 모드에 들어가기 전에 연결 실수를 드러내려는 장치입니다.
- Unity 6000.3.18f1로
SurvivalShooter폴더를 엽니다. Assets/_SurvivalShooter2023/00_Scenes/GameScene.unity를 엽니다.- Play를 누릅니다. 첫 이동이나 사격으로 스테이지가 시작됩니다.
| 항목 | 버전 |
|---|---|
| Unity | 6000.3.18f1 |
| 렌더 파이프라인 | URP 17.3.0 |
| 카메라 | Cinemachine 3.1.7 (orthographic follow) |
| 내비게이션 | AI Navigation 2.0.13 |
| 입력 | Input System 1.19.0 설치, Active Input Handling은 Both |
| 폰트 | TextMeshPro (한글 NanumSquare Bold, 영문 Luckiest Guy) |
게임플레이 코드는 레거시 Input Manager API(Input.GetAxis, Input.GetMouseButton)로 입력을 읽습니다. 2023년 구현의 입력 처리를 그대로 살린 결과이며, Input System 패키지는 설치돼 있지만 게임플레이에서 쓰지 않습니다. 두 방식이 프로젝트에 함께 있으므로 Active Input Handling을 Both로 둡니다.
아트와 모델, 오디오 등 샘플 에셋은 Unity Technologies의 Survival Shooter 튜토리얼에서 가져왔으며, 원본은 Assets/ThirdParty/OriginalSurvivalShooter/에 참조용으로 보관합니다.
게임플레이 코드와 씬 구성, 레벨 커스터마이징은 직접 작성했습니다. 원본 샘플에도 PlayerMovement처럼 이름이 같은 클래스가 있지만 구현은 서로 다르며, 이 프로젝트에서 새로 설계한 코드는 Assets/_SurvivalShooter2023/01_Scripts/ 아래에 있습니다. 어느 쪽이 빌드에 들어가는지는 asmdef 참조로 구분됩니다.
