4대 핵심 클래스
| 클래스 명 | 비유 | 핵심 특징 |
| AGameMode | Rule Maker (심판) | 규칙을 정하고 승패를 판정. 서버에만 존재. |
| AGameState | Scoreboard (전광판) | 현재 점수, 남은 시간 등 모두가 봐야 하는 정보를 공유함. |
| APlayerState | 개인 수첩 | 개별 이름, 득점 등 개인 데이터를 기록함. |
| UGameInstance | 총관리자 | 레벨이 끝나고 다음 레벨로 넘어가도 절대 사라지지 않음. |
AGameMode
키워드 : 규칙, 서버 전용, 오직 명령만(내게 명령하지마라. 명령은 내가 한다.)
역할
- 게임의 룰 관리
- 승리하려면 몇점을 내야하는지, 제한 시간은 얼마나 되는지 등 규칙을 가짐.
- Spawn 결정
- 플레이어에게 어떤 Pawn을 줄지, PlayerStart를 어디로 할지를 결정.
- 게임 흐름 제어
- 스테이지 시작, 관전모드 전환, 게임오버 등 굵직한 판정을 내림.
특징
- Server Only. 서버에만 산다!
- 멀티플레이 게임을 만들 때 가장 많이 하는 실수가 클라이언트에서 GameMode를 찾으려고 하는것.
- AGameMode는 오직 서버(Host) 메모리에만 존재한다. 즉, A라는 유저의 컴퓨터(클라이언트)에는 GameMode가 아예 존재하지 않음!
- 클라이언트에 GameMode가 있으면 게임의 규칙을 바꿔버릴 수 있기 때문에 보안을 위해 서버에만 둔다.
Base vs 일반
- AGameModeBase (가벼운 기본형)
- 싱글 플레이 게임이나 오픈월드RPG처럼 "시작과 끝이 단순한 게임"에 적합
- AGameMode (매치 시스템이 있는 무거운 버전)
- FPS처럼 먕확한 단계(State Machine)가 필요한 게임에 사용
핵심 구현 패턴
결정만 하고 AGameState에 넘기기!
AGameMode는 결정하는 고귀한 아이. 동네방네 소문내는 입이 가벼운 아이가 아님!
void AMyGameMode::StartMatch()
{
bMatchInProgress = true;
// 1. GameMode가 매치 시작이라고 결정
if(AMyGameState* GS = GetGameState<AMyGameState>())
{
// 2. 그 사실을 GameState에 넘겨서 모두가 볼 수 있게 함
GS->NotifyMatchStarted(MatchDuration);
}
}
만약 GameMode가 남은 시간 변수를 직접 가지고 있으면, 클라이언트들은 GameMode를 볼 수 없으니 화면에 남은 시간이 뜨지 않는 대참사가 발생함.
즉, GameMode는 명령만 내리고, 변수는 모두가 볼 수 있는 AGameState에 적어두는것이 정석이다.
AGameState
키워드 : 네트워크 복제, 읽기 전용
역할
GameMode 가 내린 결정이나 게임의 현재 상황을 담아서 모든 유저가 볼 수 있도록 동기화.
특징
클라이언트와 UI가 읽기만 해야한다. 데이터를 직접 수정하는 결정은 GameMode의 역할이다.
APlayerState
키워드 : 개인 데이터의 영속성(Persistence), 모두에게 복제(Replication), 한 레벨에 유지
역할 / 특징
내 캐릭터가 죽으면 그 캐릭터는 월드에서 파괴되거나 사라진다. 만약 캐릭터에 점수/킬카운트를 저장했다면 캐릭터가 죽어서 사라질 때 내 점수와 킬카운트값도 공중분해 영영 빠이빠이 되어버린다. 흑흑. 리스폰 했더니 내 화려한 전적이 0이 되어버림..
따라서 캐릭터(Pawn)은 언제든 갈아치우는 일회용 몸뚱이로 쓰고 절대 사라지면 안되는 내 데이터(이름, 점수, 팀, 핑...)는 PlayerState라는 개인 수첩에 보관하는 것이다. 이렇게 하면 캐릭터가 죽어도 수첩의 내용은 그대로이니 완전안심!
APlayerController는 나와 서버만 볼 수 있다. 즉, 다른 사람의 화면이나 컴퓨터에는 보이지 않는다.
APlayerState는 서버가 모든 클라이언트에세 복제(Replication)을 해준다.
-> 점수판을 확인할때 다른 사람들의 점수와 이름도 다 보여야하니까! PlayerController는 나한테 안보이지만 PlayerState는 모두에게 공유되기 때문에 점수판UI를 만들땐 항상 PlayerState를 뒤져서 데이터를 가져온다!
접근 방법
// ❌ 절대 금지 (안티 패턴): 전광판 배열에서 그냥 0번 인덱스 꺼내기
// 싱글 게임에선 돌아갈지 몰라도, 멀티게임에선 누가 0번일지 장담할 수 없습니다!
AMyPlayerState* BadPS = GetWorld()->GetGameState()->PlayerArray[0];
// 올바른 방법 1: 내 컨트롤러에게 "내 수첩 줘"라고 하기 (내 UI 갱신할 때)
AMyPlayerState* MyPS = MyController->GetPlayerState<AMyPlayerState>();
// 올바른 방법 2: 클라이언트가 점수를 얻고 싶을 때 (핵 방지용 RPC 요청)
// "내 수첩아, 나 50점 먹었으니까 서버에 적용해줘!"
MyPlayerState->Server_AddScore(50);
GameInstance
키워드 : 불사신, 레벨 전환 이사 전문
역할
- 전체 누적 데이터 관리
- 플레이어의 총 누적 골드, 여태까지 클리어 한 스테이지 번호 등 게임 전체를 관통하는 데이터를 들고있기에 가장 좋다.
- 레벨 전환의 총지휘관
- 레벨을 열고 닫는 권환을 실행하기 가장 좋은 위치이다.
특징
- 수명
- 게임 프로그램을 킬 때 태어나서, 게임을 완전히 종료할 때 죽는다.
- 불사신
- 로비 레벨, 마을 레벨 심지어 메인 메뉴 화면으로 돌아가더라도 GameInstance만큼은 메모리에서 절대 사라지지 않고 단 하나만 계속 유지된다.
APlayerController
내가 이 캐릭터의 영혼이다 중생들아
유저가 키보드를 누르고 마우스를 움직이는 모든 행동을 게임 속 세계로 전달하는 컨트롤러 역할
하는 일
- 입력 처리 (Input Binding)
- 플레이어의 입력을 받아 처리한다.
- 육체 빙의 (Possess / UnPossess)
- 월드에 배치된 캐릭터(APawn)에 영혼을 불어넣는 역할을 한다. 캐릭터가 죽으면 빠져나오고 부활하면 새 캐릭터에 다시 빙의한다.
- 카메라 및 UI 관리
- PlayerCameraManager를 관리하고, 화면에 마우스 커서를 띄우거나 마우스 클릭 기반의 HUD/UMG 위젯 UI를 생성하고 조작하는 주체가 된다.
서버와 본인 컴퓨터에만 존재
멀티플레이에서 컨트롤러의 메모리 구조는 대단히 독특함!
- 서버 (HOST)
- 모든 점속자의 PlayerController를 전부 가지고 관리한다.
- 누가 무슨 행동을 하느지 알아야하니까!
- 내 컴퓨터 (로컬 클라이언트)
- 오직 내 것 하나만 존재한다. 다른 사람의 PlayerController는 내 컴퓨터 메모리에 아예 생성되지 않는다.
- 다른 사람 컴퓨터
- 내 PlayerController가 존재하지 않는다.
AIController
사람이 조종하는 캐릭터가 아닌, 컴퓨터가 조종하는 몬스터나 NPC의 영혼역할을 맡는다.
입력이나 UI를 처리하는 기능이 쏙 빠져있는 대신, Behavior Tree나 주변을 감지하는 UAIPerceptionComponent를 장착해서 스스로 Pawn을 조종하게 된다.
APawn vs ACharacter
움직이는 육체들의 등급
컨트롤러(영혼)가 빙의할 수 있는 모든 물리적인 몸뚱이는 APawn에서 출발한다. 언리얼은 이를 크게 두 가지로 나누어 제공한다.
APawn
특징
인간이 아닌 형태의 탈것이나 물체를 만들 때 주로 상속 받는다.
아주 기본적인 이동 컴포넌트(MovementComponent)만 가지고 있어서, 하늘을 날거나 구르는 물리 로직을 개발자가 커스텀하기에 좋다.
ACharacter
특징
사람처럼 두 발로 걷고, 달리고, 점프하는 캐릭터를 만들 때 쓴다. RPG나 FPS게임의 주인공들은 99% 이 녀석을 상속받는다.
언리얼이 미리 엄청난 기능들을 기본으로 추가해두었다.
- CharacterMovementComponent
- 걷기, 달리기, 점프, 수영, 비행 등 인간형 이동 로직이 이미 완벽하게 구현되어있다.
- CapsuleComponent
- 부딪히는 물리 충돌 체형
- SkeletalMeshComponent
- 애니메이션을 입힐 수 있는 뼈대 메쉬
특수 Pawn
ADefaultPawn
자유 비행 카메라용. 에디터/디버깅에서 자주 쓰인다.
ASpectatorPawn
매치 관전 모드용. 충돌 없이 자유 이동 가능.
Framework 로딩 순서 (LifeCycle)
1단계: 가장 먼저 태어나는 맏형 (GameInstance)
- 게임이 켜지자마자 UGameInstance::Init()이 실행된다.
- 주의: 이때는 아직 월드(World)도 없고, 다른 4대장들도 아예 안 태어난 상태. 여기서 GetWorld()나 GetPlayerController()를 호출하면 무조건 튕긴다!
2단계: 레벨이 열리며 태어나는 동생들 (응애 응애)
- 맵이 로드되면 GameMode => GameState => PlayerController => PlayerState => Pawn 순서로 순식간에 스폰됨.
3단계: PostLogin()과 StartPlay()
- 많은 초보자가 BeginPlay()에서 모든 걸 해결하려고 한다. 하지만 BeginPlay는 애들의 호출 순서가 뒤죽박죽이라 위험!
- 가장 안전한 타이밍: 심판(GameMode)의 PostLogin() 함수. 이 함수가 실행되는 시점에는 플레이어의 영혼(PlayerController)과 수첩(PlayerState)이 완벽하게 세팅되어 연결된 상태이므로, 멀티플레이어 초기화 코드를 짜기에 가장 안전의 정석이다.
'내일배움캠프' 카테고리의 다른 글
| 내일배움캠프 언리얼트랙 41일차 - 보안요원 State Tree (0) | 2026.06.19 |
|---|---|
| 내일배움캠프 언리얼트랙 40일차 - 보안요원 AI Controller (0) | 2026.06.18 |
| 내일배움캠프 언리얼트랙 35일차 - TA 1강 (0) | 2026.06.11 |
| 내일배움캠프 언리얼트랙 34일차 - 과제04 (0) | 2026.06.10 |
| 내일배움캠프 언리얼트랙 33일차 (0) | 2026.06.10 |