서론
냅다 오브젝트를 만들고, 코드부터 짠다면 금세 스파게티 코드가 될 것이다.
그러니, 본격적으로 코드와 오브젝트를 생성하기 전에, 코드를 어떤 식으로 짜고, 어떻게 관리하며, 어떻게 확장하는지 방법을 찾아보자.
전문성의 한계
개발자라고 한들, 아직 회사를 다니지 않은 대학생에 불과하기에, 실제 실무에서 어떻게 작업이 이뤄지는지 나는 알 수 없다.
그렇기에, 우선 클로드에게 역할을 부여하고, 어떤 것이 필요한지 요청할 것이다.
개인 맞춤 설정
그 전에, 먼저 클로드에게 개인 맞춤 설정을 입력해보자.

위와 같이 간단한 프롬프트를 세팅해두었다. 이로써, 단순히 희미한 요청 사항에도 즉각적으로 반영하는 일이 없길 기도해본다.
이제, 본격적으로 작업에 착수해보자.
지금부터 너는 메인 개발자야.

우선 클로드의 역할을 명확히 하고, 앞으로 어떻게 프로젝트를 진행할지 설명하였다. 이에 대한 클로드의 답변은 이렇다.


기획서에서 부족한 부분을 짚었고, 엄밀하지 않은 부분들을 요청한다.
이제, 각 질문에 답을 해보자.
아키텍처 패턴. 무엇으로 결정할 것인가?
Input System은 New를 사용할 것이고, 게임은 2D로 개발한다.
MVP로 처음부터 마음이 기울어 있었지만, 이왕이면 이번 프로젝트를 통해 내 실력도 키우는 쪽이 좋을 것이다. 이에 MVC와 MVP 각각의 장단점을 상세히 알려달라고 했다.

답변이 길어지는 만큼, 앞으로는 스크린샷 대신 접은 글로 답변을 올리겠다. 내용이 궁금하다면 아래 글을 펴보면 된다.
좋은 선택들입니다. 3번 질문에 먼저 답변드릴게요.
MVC vs MVP — 게임 개발 맥락에서의 비교
MVC (Model - View - Controller)
Model ←→ Controller ←→ View
↑________________________↑
View가 Model을 직접 관찰
- Model: 데이터와 게임 상태 (HP, 스킬 쿨타임 등)
- View: 화면에 보이는 것 (UI, 애니메이션)
- Controller: 입력을 받아 Model을 변경
장점:
- 구조가 직관적이고 Unity 개발자에게 친숙함
- View가 Model을 직접 관찰(Observer)할 수 있어 반응형 UI 구현이 간단
단점:
- View와 Model 사이에 의존성이 생겨 테스트가 어려움
- Controller가 비대해지는 "Massive Controller" 문제 발생 빈도 높음
- 이 프로젝트처럼 캐릭터별 고유 메커니즘이 많으면, Controller 안에 분기문이 폭발할 위험
MVP (Model - View - Presenter)
Model ←→ Presenter ←→ View
(View는 Model을 절대 모름)
- Model: 데이터와 비즈니스 로직
- View: 오직 표시만 담당. Presenter가 시키는 대로만 움직임 (수동적)
- Presenter: Model과 View 사이의 모든 흐름을 중재
장점:
- View와 Model이 완전히 분리되어 단위 테스트가 용이
- View가 수동적(Passive)이라, UI 교체나 연출 변경이 로직에 영향을 주지 않음
- 캐릭터별 Presenter를 분리하면 고유 메커니즘 확장이 깔끔함
단점:
- Presenter와 View 간의 인터페이스(Interface)를 명시적으로 정의해야 해서 초기 설계 비용이 높음
- 소규모 프로토타입에서는 오버엔지니어링처럼 느껴질 수 있음
이 프로젝트에 대한 저의 추천 — MVP
이유는 세 가지입니다.
첫째, 캐릭터 4종의 고유 메커니즘이 각자 다른 로직을 가지고 있어서, View(연출)와 Logic(메커니즘)의 분리가 나중에 반드시 필요해집니다. MVC는 이 지점에서 Controller가 뒤엉킬 가능성이 높습니다.
둘째, 기획 변경 대응 측면에서 MVP가 유리합니다. 예를 들어 암살자의 잔상 연출 방식이 바뀌어도, Presenter의 로직은 건드리지 않고 View만 교체할 수 있습니다.
셋째, 장기적으로 테스트 코드를 붙일 계획이라면, View 의존성이 없는 Presenter는 Unity 없이도 순수 C#으로 테스트가 가능합니다.
4번 씬 전략도 동의합니다. 단일 씬으로 시작 → 추후 Additive 분리는 중간 전환이 충분히 가능한 옵션이고, 프로토타입 속도를 위해 올바른 선택입니다.
그럼 다음 단계로 넘어갈 준비가 됐습니다.
아래 두 가지를 이어서 결정하면 바로 프로젝트 규칙 문서 초안을 작성할 수 있습니다.
**결정이 필요한 마지막 두 가지:**선택 기다리고 있겠습니다! 이 두 가지가 결정되면, 바로 폴더 구조 + 네임스페이스 + 코딩 컨벤션을 담은 프로젝트 규칙 문서 초안을 작성해드릴게요.
그러자 클로드는 친절하게도, 두 방식의 장단점을 알려주었다. 물론, 정확한 예시까지 요청하면 더 이해가 잘 되겠지만, 이정도로도 문제는 없었다.

오히려 놀라운 건 이쪽이었다. 예상대로 클로드가 MVP를 추천하긴 했지만, 답변 방식이 주관식이 아닌, 객관식으로 나타난 것이다.

1번 질문엔 각 방식의 장단점을 설명해달라 했고, 2번 질문은 가볍게 1번을 선택했다. 그러자 위처럼 프롬프트가 입력되었다.
이후 클로드가 각 방식의 코드 예시와 함께 장단점을 설명해주었는데, 내용은 아래와 같다.
View ↔ Presenter 통신 방식 3가지 상세 비교
1. C# Interface 정의
// View가 구현해야 할 계약
public interface IPlayerView
{
void UpdateHP(float current, float max);
void PlayDodgeAnimation();
event Action OnTapInput;
}
// Presenter는 Interface만 알고 있음
public class PlayerPresenter
{
private IPlayerView _view;
public PlayerPresenter(IPlayerView view) { _view = view; }
}
장점:
- View를 Mock 객체로 교체할 수 있어 순수 C# 단위 테스트 가능
- 계약이 명시적이라 신입 개발자가 "View는 이것만 구현하면 된다"는 걸 즉시 파악
- SOLID의 DIP(의존성 역전 원칙)에 가장 충실
단점:
- Interface 파일이 시스템마다 늘어나 초기 보일러플레이트 비용이 높음
- 기획 변경 시 Interface 수정 → 구현체 전부 수정의 연쇄가 발생할 수 있음
2. UnityEvent / C# event
// View
public class PlayerView : MonoBehaviour
{
public event Action OnTapInput;
public event Action<Vector2> OnDragInput;
public void UpdateHP(float current, float max)
=> hpBar.fillAmount = current / max;
}
// Presenter가 이벤트를 구독
public class PlayerPresenter
{
public PlayerPresenter(PlayerView view)
{
view.OnTapInput += HandleTap;
}
}
장점:
- Unity 개발자에게 가장 친숙한 패턴, 러닝커브 낮음
- Interface 없이도 느슨한 결합 구현 가능
- UnityEvent는 Inspector에서 연결 가능해 비개발자(기획자)도 확인 용이
단점:
- 이벤트 구독/해제(+=, -=) 관리를 누락하면 메모리 릭 발생
- View와 Presenter가 구체 타입을 서로 알아야 해서 Interface 방식보다 결합도가 높음
- 이벤트가 많아질수록 어디서 누가 구독 중인지 추적이 어려워짐
3. ScriptableObject 이벤트 채널
// SO 이벤트 채널 에셋
[CreateAssetMenu]
public class GameEvent : ScriptableObject
{
private List<GameEventListener> _listeners = new();
public void Raise() => _listeners.ForEach(l => l.OnEventRaised());
}
// View는 채널만 참조
public class PlayerView : MonoBehaviour
{
[SerializeField] private GameEvent _onTapEvent;
void OnTap() => _onTapEvent.Raise();
}
// Presenter도 채널만 참조 (서로를 전혀 모름)
public class PlayerPresenter : MonoBehaviour
{
[SerializeField] private GameEvent _onTapEvent; // 같은 에셋 참조
}
장점:
- View와 Presenter가 서로의 존재를 완전히 모름 → 최고 수준의 디커플링
- 이벤트 채널이 에셋이라 Inspector에서 연결, 시각적으로 흐름 파악 가능
- 씬을 넘나드는 통신도 자연스럽게 처리 (추후 씬 분리 시 유리)
단점:
- SO 에셋 파일이 시스템마다 생성되어 프로젝트가 커지면 에셋 관리 복잡도 증가
- 타입 파라미터 지원을 위해 제네릭 SO를 별도 구현해야 함 (보일러플레이트)
- 이벤트 흐름이 코드가 아닌 에셋 연결로 관리되어 코드 레벨 디버깅이 어려움
이 프로젝트에 대한 저의 추천
세 방식을 혼합 사용하되, 계층을 명확히 구분하는 것을 추천합니다.
상황 추천 방식| Presenter ↔ View 계약 | C# Interface (테스트 가능성 확보) |
| 시스템 간 느슨한 통신 (Input→Combat 등) | C# event (친숙하고 빠름) |
| 씬 경계를 넘는 글로벌 이벤트 (추후) | SO 이벤트 채널 (디커플링 최대화) |
프로토타입 단계에서는 C# Interface + C# event 조합으로 시작하고, 씬이 분리되는 시점에 필요한 곳에만 SO 채널을 도입하는 방식이 가장 현실적입니다.
어떻게 생각하시나요? 이 방향으로 가닥이 잡히면, 지금까지 결정된 내용을 전부 정리해서 프로젝트 규칙 문서 초안을 작성해드리겠습니다.
각 방법들의 장단점이 뚜렷했기에, 사실 클로드 말대로 필요한 곳에, 어떻게 쓸지 정해두는 게 가장 좋은 방법이다.
이 내용을 바탕으로, 먼저 문서 초안을 작성해달라고 했다. 아직 정해진 게 많이 없기에, 간단한 내용만 들어있고, 추후 대화 후 수정으로 내용을 채우거나, 혹은 직접 수정할 생각도 하고 있었는데....

생각보다 어마어마한, 본격적인 문서가 생성되었다. 중간에 md 확장자를 직접 생성할 수 없다고 떴었는데, 이에 복붙으로 생성해야하나 싶었던 찰나, cs 파일 생성 -> 파일 실행으로 md 파일 생성이라는 우회 경로를 찾아내었다. 솔직히, 이정도일 거라곤 예상 못 했는데, 성능이 한참 뛰어나다.

내용을 볼 수 있게, 블로그에 MD 파일을 업로드해두겠다.
MCP의 한계

다만, 다시 읽기를 테스트해보니 md 파일을 직접적으로 읽을 순 없다고 한다. 이에 어차피 얘 혼자 개발할 거니, cs를 함께 두는 편이 좋아보였다.

이에 특정 타이밍에, cs 파일과 md 파일을 비교하고, 검증한 후, 다르다면 cs가 자신을 갱신하는 방식을 채택하기로 했다.
이로써 앞으로 사람이 md 파일을 수정하더라도 클로드가 다른 규칙으로 일하지 않을 것이고, 이로써 협업 시 문제가 발생하지 않을 것이다. (물론 대부분, 아니 사실상 전부 클로드가 하겠지만.)
오류 발생

cs를 통해 우회하는 과정에서, 파싱이 잘못되어 에러가 발생했다.
public static string GetCachedContent()
{
return
// <GUIDELINES_CACHE_START>
# 프로젝트 개발 지침서 (Project Guidelines)
> **버전**: v0.1.0
> **최초 작성일**: 2026-03-05
> **목적**: 본 문서는 프로젝트 전반의 아키텍처, 코딩 컨벤션, 폴더 구조, 협업 규칙을 정의합니다.
> 모든 개발자(인간 및 AI)는 코드 작성 전 반드시 이 문서를 숙지하고, 작업 시 지침으로 삼아야 합니다.
---
## 1. 프로젝트 개요
| 항목 | 내용 |
|------|------|
| 장르 | 싱글 플레이 실시간 액션 RPG |
| 플랫폼 | 모바일 (Android / iOS), PC 테스트 지원 |
| 화면 방향 | 세로 모드 (Portrait) |
| 렌더 파이프라인 | URP 2D |
| 조작 | 화면 하단 40% 영역, 단일 손가락(엄지) 조작 / PC 마우스 지원 |
| 목표 | 프로토타입 → 안정적 서비스 → 수익화 |
### 핵심 조작 상태 (Input States)
| 입력 | 상태 | 설명 |
이처럼 return 뒤에 md 파일의 내용을 바로 갖다넣으면서 문제가 발생했고, 이를 클로드에 알리자 수정을 시작했다.

간단한 문제였던 만큼, 해결은 금방 되었다. 물론 이런 에러도 없이 진행됐다면 더 좋았겠지만, 프롬프트 한번 더 적는 정도고, 인간도 오류를 만들고 고쳐나가며 개발하니 이정도야 괜찮다.
폴더 구조 정리
이제, 프로젝트 폴더를 어떻게 정리할지 얘기해보았다.
먼저, 클로드가 생각하는(추천하는) 방식을 알아보았다.
좋아. 문제가 해결됐네. 이제 다음으로 넘어가보자.
이제 폴더 구조에 대한 아이디어를 나눌 차례야. 먼저, 네가 생각하는 좋은 폴더 구조는 어떤 거야?
좋은 폴더 구조의 핵심은 "이 파일이 어디 있는지 파일명을 보기 전에 폴더 경로만으로 알 수 있어야 한다" 는 것입니다.
그 기준에서 제가 생각하는 원칙은 세 가지입니다.
원칙 1. 기술 계층보다 기능(도메인) 중심으로 묶기
많은 프로젝트가 이렇게 시작합니다.
Scripts/
├── Models/
├── Views/
└── Presenters/
하지만 이 구조는 전투 관련 파일을 찾으려면 Models, Views, Presenters 세 곳을 모두 뒤져야 합니다. 기능이 늘어날수록 각 폴더가 비대해지고, 관련 없는 파일들이 한 폴더에 섞입니다.
반면 이렇게 하면:
Scripts/
├── Combat/
│ ├── Model/
│ ├── View/
│ └── Presenter/
├── Input/
└── Characters/
Combat을 통째로 다른 프로젝트에 옮기거나, 삭제하거나, 담당자를 지정하기가 훨씬 쉬워집니다. 응집도(cohesion) 가 높아지는 구조입니다.
원칙 2. 에셋 종류와 스크립트는 분리하되, 같은 논리적 그룹 안에 있어야 함
Prefabs, ScriptableObjects, Art는 Scripts와 별도 폴더에 두는 게 맞습니다. Unity의 에셋 파이프라인이 그렇게 작동하고, 아티스트와 기획자가 코드 폴더를 열 이유가 없기 때문입니다.
다만 네이밍은 일치시켜야 합니다.
Scripts/Characters/Warrior/
Prefabs/Characters/Warrior/
ScriptableObjects/Characters/Warrior/
어느 폴더에 있든 Warrior를 찾으면 된다는 일관성이 생깁니다.
원칙 3. 성장 경로를 미리 설계하기
프로토타입 단계에서 만든 폴더 구조가 나중에 걸림돌이 되는 가장 흔한 이유는, 나중에 생길 것들을 위한 자리를 처음부터 만들어두지 않아서입니다.
예를 들어 지금은 캐릭터가 4종이지만, 나중에 몬스터, 보스, NPC가 생깁니다. 그때 Characters/ 옆에 Enemies/가 생기면 공통 로직(IDamageable 등)이 어디 있어야 하는지 애매해집니다. 처음부터 Core/에 공통 인터페이스 자리를 잡아두면 이 혼란이 없습니다.
이 프로젝트에 제가 제안하는 구체적 구조
지침서에 정의된 것보다 조금 더 구체화한 버전입니다.
Assets/_Project/
│
├── _Docs/ # 개발 문서
│ └── Editor/
│
├── Scripts/
│ ├── Core/ # 프로젝트 전체 공통
│ │ ├── Interfaces/ # IDamageable, IHealable 등
│ │ ├── Base/ # CharacterPresenterBase 등 추상 클래스
│ │ └── Utils/ # 확장 메서드, 수학 유틸 등
│ │
│ ├── Input/ # 입력 시스템 전담
│ │ ├── GestureRecognizer.cs
│ │ └── InputStateEvent.cs
│ │
│ ├── Combat/ # 전투 공통 시스템
│ │ ├── Model/
│ │ ├── View/
│ │ └── Presenter/
│ │
│ ├── Characters/ # 플레이어 캐릭터
│ │ ├── Base/ # CharacterPresenterBase (캐릭터 전용 공통)
│ │ ├── Warrior/
│ │ ├── Assassin/
│ │ ├── Rapier/
│ │ └── Ranger/
│ │
│ ├── Enemies/ # 적 (추후 확장 자리 선점)
│ │
│ ├── UI/
│ │ ├── HUD/
│ │ └── Common/
│ │
│ └── Data/ # SO 클래스 정의
│ ├── Characters/
│ └── Skills/
│
├── ScriptableObjects/ # SO 에셋 인스턴스
│ ├── Characters/
│ └── Skills/
│
├── Prefabs/
│ ├── Characters/
│ ├── Enemies/
│ ├── Skills/
│ └── UI/
│
├── Scenes/
│ ├── SampleScene.unity
│ └── _Test/ # 기능 단위 테스트 씬
│
├── Art/
│ ├── Sprites/
│ │ ├── Characters/
│ │ ├── Enemies/
│ │ └── UI/
│ ├── Animations/
│ └── VFX/
│
└── Audio/
├── BGM/
└── SFX/
지침서에 정의된 구조와 큰 틀은 같되, Enemies/ 자리를 미리 잡아두고, Art/ 하위를 카테고리별로 나눈 것이 추가된 부분입니다.
이 구조에서 수정하거나 추가하고 싶은 부분이 있으신가요? 확정되면 바로 유니티에 폴더를 생성하겠습니다.
공감되는 부분이 있었지만, 몇 가지 추가 아이디어를 전달했다.
- 인덱싱을 이용한 폴더 그룹화 -> 프로그래머, 아트, 기획자가 자신의 폴더들이 어디쯤 위치하는지 쉽게 파악 가능
- Private 저장소의 존재
인덱싱 간격, Private과 Public의 역할 분리 등을 계속 조정해나갔고, 폴더 생성 후 합의된 내용을 지침서에 업데이트 하는 것으로 작업을 마무리했다.


폴더가 잘 만들어졌다! 지침서 역시 제대로 갱신되었다.

중간에 사소한 이슈도 있었지만, 누구나 실수는 할 수 있으니. 점점 나아질 거라 믿고 해보자.
컨텍스트 저장
마지막으로, 클로드의 섹션이 바뀌거나, 컨텍스트를 잊을 때에 대비해, 프로젝트 내에 AI용 컨텍스트도 저장하게 만들어보았다. 역시나 프롬프트로 대화하며 계획을 짜고, 승인 후 클로드가 작업하고, 검증하며 작업했다.

개발 도중 어려움을 겪었을 때, 해당 내용을 즉시 컨텍스트에 추가하게 하여, 이미 겪은 문제를 또 겪지 않게 하였다.


또한, 컨텍스트를 갱신할 때, 작업 중 제약 발견 시 즉시 갱신하는 항목도 추가했다.
이로써, 제대로 개발할 준비가 끝났다.
마무리
저번 시간에 단순히 클로드와 유니티를 연결했다면, 이번 시간엔 프로젝트를 어떻게 관리할지, 앞으로 클로드가 어떻게 행동할지 정하는 단계였다. 귀찮을 수 있지만, 이번 작업이 프로젝트의 기반이 되어, 흔들리지 않게 해주길 바란다.
이제 다음 회차에선, 본격적인 프로토타이핑을 위한 계획과 To-do List를 만들고, 해당 계획에 따라 하나씩, 시스템을 직접 만들어보자.
'게임 제작 기록 > AI 게임 개발 일지' 카테고리의 다른 글
| [AI로 모바일 게임 개발 - 6] 플레이어 이동 버그 수정 (0) | 2026.03.11 |
|---|---|
| [AI로 모바일 게임 개발 - 5] 기반 코드 생성, 플레이어 이동 구현 (1) | 2026.03.07 |
| [AI로 모바일 게임 개발 - 4] DI, 테스트 전략 수립, 프로토타이핑 계획 수립 (0) | 2026.03.07 |
| [AI로 모바일 게임 개발 - 2] 유니티 MCP로 클로드 연동하기 (2) | 2026.03.05 |
| [AI로 모바일 게임 개발 - 1] AI와 기획하기 (0) | 2026.03.05 |