GameMode, GameState, PlayerController, PlayerState, Pawn, AnimInstance가 각각 왜 따로 존재하는지

 

1. 두 축으로 나누기

멀티플레이의 기본 축은 두 가지다

권한 축: 서버에만 존재하는가, 클라이언트에 복제되는가

개인 축: 나 자신에게만 보이는가, 모두에게 공개되는가

 

GameMode서버에만 존재하며 라운드, 리스폰, 승패 판정 같은 게임 규칙 본체를 담는다.

GameState는 전체 클라이언트에 복제되며 그 규칙의 결과를 모두에게 보여주는 전체 상태다.

PlayerController는 자기 자신에게만 존재하며 입력 처리와 카메라를 담당하는 플레이어의 의지

PlayerState는 전체 클라이언트에 복제되며 점수나 닉네임처럼 공개되는 개인 데이터를 담는데 Pawn이 죽어도 유지된다는 게 특징이다

Pawn/Character는 서버와 클라이언트 양쪽에 존재하는 실제 몸으로 PlayerController가 Possess로 빙의한다

AnimInstance는 Character와 별도의 객체로 Character의 상태값을 받아 애니메이션 재생을 결정한다

 

Pawn은 죽으면 사라지고 새로 생기지만 점수 같은 데이터는 사라지면 안 되기 때문에 Pawn이 아니라 PlayerState에 둔다

리스폰 시 PlayerState::CopyProperties()가 호출되는데 이 함수가 "몸이 바뀌어도 데이터는 이어진다"는 PlayerState의 존재 이유를 보여준다

 

전체 흐름

접속 단계에서는 플레이어가 접속하면 GameMode::PostLogin()이 호출되고, PlayerController와 PlayerState가 생성된다.

이어서 GameMode::RestartPlayer()Pawn을 스폰하고, PlayerController::OnPossess(Pawn)으로 둘이 연결된다

게임플레이 중에는 매 프레임마다 입력이 들어오면 PlayerController가 처리해서 Character::Move()를 실행시키고, Character의 Velocity가 변하면 AnimInstance::NativeUpdateAnimation()이 그 Velocity를 읽어서 애니메이션을 갱신한다.

 

이벤트가 발생할 때

예를 들어 점수를 획득하면 Character에서 사건이 발생하고 PlayerState::AddScore()가 호출된다

Replicated 변수가 바뀌면 모든 클라이언트에 복제되어 OnRep_Score()가 실행되고, GameState의 전역 카운트도 갱신되어 다시 모두에게 복제된다

 

정리하면 GameMode가 위에서 전체를 지휘하고, 그 아래 사람 쌍(Controller+State)몸 쌍(Character+AnimInstance)Possess로 연결되며, 사건의 결과는 PlayerState에서 GameState 순서로 위로 보고되며 퍼진다.

 

C++ 베이스 + Blueprint 상속 패턴

C++을 고치면 매번 컴파일이 필요하지만 Blueprint는 즉시 적용된다

그래서 로직(함수, UPROPERTY)은 C++에 정의하고, 수치나 에셋 연결 같은 값 조정은 Blueprint에서 한다.

UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
float MoveSpeed;

 

+ Recent posts