핵심 정리
text
MonoBehaviour
-> 입력, lifecycle, scene wiring
순수 C# class
-> 규칙, 계산, 상태 전이구조 이해
- Unity 프로젝트가 커질수록 가장 중요한 구조 선택 중 하나는 "무엇을
MonoBehaviour안에 둘 것인가"입니다. 모든 규칙과 상태를 컴포넌트 안에 몰아넣으면 테스트도 어렵고, 씬 의존도도 커지고, 재사용성도 떨어집니다. - 반대로
MonoBehaviour를 입력 수집, 참조 연결, lifecycle 처리, 뷰 갱신처럼 Unity에 꼭 필요한 역할로 얇게 두고, 게임 규칙과 계산은 순수 C# 클래스로 분리하면 훨씬 다루기 쉬워집니다. - 예를 들어 체력 계산, 쿨다운 규칙, 인벤토리 정렬, 퀘스트 상태 전이는 대부분 엔진 없이도 돌아갈 수 있습니다. 이런 부분이 순수 클래스에 있으면 EditMode 테스트로 빠르게 검증할 수 있습니다.
ScriptableObject는 설정값과 공유 데이터를 분리하는 데 도움을 줄 수 있고,MonoBehaviour는 그 데이터를 씬과 연결하는 adapter 역할을 맡게 만들 수 있습니다.- 결국 테스트 가능한 Unity 아키텍처란 거창한 프레임워크보다 경계 설정입니다. "이 로직은 엔진이 꼭 필요한가?"를 계속 묻는 습관이 구조를 결정합니다.
체크포인트
| 상황 | 적합한 선택 |
|---|---|
| 씬 연결, lifecycle, 입력 수집 | MonoBehaviour 책임으로 유지 |
| 체력 계산, 쿨다운 등 규칙 로직 | 순수 C# 클래스로 분리 → EditMode 테스트 |
| 씬 간 공유 설정·데이터 | ScriptableObject 컨테이너 |
| 테스트 작성이 어려움 | 설계 경고 → Unity 의존이 과도한지 점검 |
주의할 점
모든 것을 추상화 계층으로 나누는 것도 과합니다. 반복 수정이 잦고 규모가 커질 때 분리가 이득을 주며, 소형 프로토타입에서는 단순한 MonoBehaviour가 더 낫습니다.
csharp
// ❌ MonoBehaviour에 규칙 로직 혼재 → 테스트 불가
public class PlayerHealth : MonoBehaviour
{
public void TakeDamage(int dmg)
{
hp -= dmg;
if (hp <= 0) Die(); // 엔진과 강결합된 규칙
}
}
// ✅ 규칙은 순수 C# → EditMode 테스트 가능
public class HealthSystem // MonoBehaviour 아님
{
public int Hp { get; private set; }
public bool IsDead => Hp <= 0;
public void TakeDamage(int dmg) => Hp = Math.Max(0, Hp - dmg);
}
public class PlayerHealth : MonoBehaviour
{
private HealthSystem _health = new HealthSystem();
// MonoBehaviour는 연결만 담당
}참고 링크
3 sources