TIL

[UE5] ProjectFT#3 Unreal Subsystem 이해 및 프로젝트 적용

think95592 2026. 7. 7. 20:10

Subsystem을 사용하게 된 이유

프로젝트를 진행하면서 여러 Actor가 동일한 기능을 담당하거나, 전역적으로 관리해야 하는 기능들이 생기기 시작했다.

처음에는 각 Actor나 Widget에서 직접 처리했지만, 기능이 늘어날수록 책임이 분산되고 코드 의존성이 높아지는 문제가 발생했다.

이를 해결하기 위해 Subsystem을 활용하여 공통 기능을 한곳에서 관리하는 구조를 적용하였다.


Subsystem이란?

Subsystem은 게임 전체에서 공통으로 사용하는 기능을 관리하기 위한 관리자 클래스이다.

Actor처럼 월드에 배치하지 않아도 자동으로 생성되며, 필요한 곳에서 언제든 접근할 수 있다.

예를 들어

  • UI 관리
  • 퀘스트 관리
  • 상점 관리
  • 게임 진행 흐름 관리

처럼 특정 Actor에 속하지 않는 기능을 담당하기에 적합하다.


GameInstanceSubsystem과 WorldSubsystem의 차이

언리얼에는 여러 종류의 Subsystem이 존재하지만, 가장 많이 사용하는 두 가지는 다음과 같다.

GameInstanceSubsystem

게임이 실행되는 동안 하나만 존재한다.

게임 시작
    │
GameInstanceSubsystem 생성
    │
레벨 이동
    │
계속 유지
    │
게임 종료

사용 예시

  • UIManager
  • Save 관리
  • 게임 진행 데이터
  • 플레이어 프로필

WorldSubsystem

현재 월드(Level)에 종속된다.

레벨 A
    │
WorldSubsystem 생성
    │
레벨 변경
    │
기존 삭제
    │
새로운 WorldSubsystem 생성

사용 예시

  • AI 관리자
  • 스폰 관리자
  • 현재 맵 전용 시스템

SaveGame과의 역할 분리

처음에는 SaveGame이 모든 데이터를 관리하는 것처럼 생각했지만,

실제로는 역할이 다르다.

SaveGame

영구적으로 저장해야 하는 데이터를 담당한다.

예시

  • 플레이어 골드
  • 해금된 아이템
  • 옵션 설정

Subsystem

게임이 실행되는 동안 필요한 로직을 담당한다.

예시

  • 현재 퀘스트
  • UI 상태
  • 게임 진행
  • 이벤트 처리

즉,

SaveGame은 데이터 저장소,

Subsystem은 기능 관리자라는 차이를 이해하게 되었다.


Actor에서 Subsystem으로 책임 이동

기존에는 Actor가 직접 여러 기능을 수행했다.

Player
├─ UI 열기
├─ 퀘스트 확인
├─ 게임 진행 확인
└─ 화면 전환

리팩터링 이후에는

Player
    │
    ├── UIManagerSubsystem
    ├── ObjectiveSubsystem
    └── 기타 Subsystem

처럼 필요한 기능을 Subsystem에 요청하는 구조로 변경하였다.

덕분에 Player는 플레이어의 행동에만 집중하고,

Subsystem은 각자의 기능을 담당하도록 역할을 분리할 수 있었다.


UIManagerSubsystem 구조

UI 관련 기능을 하나의 Subsystem에서 관리하도록 설계하였다.

UIManagerSubsystem

├─ MainWidget 생성
├─ 패널 열기
├─ 패널 닫기
├─ WidgetSwitcher 제어
└─ UI 상태 관리

이렇게 구성하면 여러 Actor가 UI를 직접 제어하지 않아도 되고,

UI 변경 사항도 한 곳에서 관리할 수 있다.


ObjectiveSubsystem 구조

게임 목표와 퀘스트 진행을 관리하는 역할을 담당한다.

ObjectiveSubsystem

├─ 현재 목표 관리
├─ 퀘스트 진행 확인
├─ 완료 여부 검사
└─ 다음 목표 갱신

퀘스트 관련 로직이 하나의 시스템으로 모이면서 관리가 훨씬 쉬워졌다.


느낀 점

Subsystem은 단순히 전역 객체를 만드는 기능이 아니라 공통 기능을 책임별로 분리하기 위한 구조라는 점을 이해하게 되었다.

특히 Actor에서 직접 처리하던 기능을 Subsystem으로 옮기면서 클래스 간 의존성을 줄일 수 있었고, 프로젝트 규모가 커져도 기능별로 관리하기 쉬운 구조를 만들 수 있었다.

앞으로도 특정 Actor에 속하지 않는 기능이라면 먼저 Subsystem으로 분리하는 것이 유지보수와 확장성 측면에서 더 좋은 선택이라는 것을 배웠다.