플레이중인 게임의 정보를 처리하는 클래스는 크게 GameMode와 GameState 둘로 나뉘어진다.
GameMode
게임 프레임워크의 바탕은 GameMode이다. GameMode에서는 게임의 규칙을 설정한다. 플레이어 스폰 처리도 담당한다.
보통 플레이 도중 자주 바뀌는 데이터는 없어야 하며, 서버에만 존재하므로 클라이언트에서 알아야 하는 휘발성 데이터는 절대 넣어선 안된다. 가장 제약이 없다는 게임일지라도 토대가 되는 규칙들이 존재하며, 이러한 규칙들이 게임모드를 이룬다. 가장 기본적인 수준에서 간단하게 예를들어 보자면 다음과같다.
- 존재하는 플레이어와 관람자의 수, 허용된 플레이어와 관람자의 최대 인원.
- 플레이어가 게임에 들어오는 방식, 스폰 위치 선택 규칙과 기타 스폰/리스폰 동작 포함 가능.
- 게임 일시정지 가능 여부, 게임 일시정지 처리 방식.
- 레벨간의 전환, 게임의 시네마틱 모드 시작 여부 포함.
class AGameModeBase
모든 게임 모드는 이것의 서브클래스로 게임이 제공하는 경기 포맷, 미션 유형 등에 대해 AGameModeBase 클래스의 서브 클래스를 만들 수도 있으나, 한 번에 하나의 게임모드만 사용할 수 있다. 게임 모드 액터는 UGameEngine::LoadMap()를 통해 플레이할 레벨을 초기화시킬 때마다 인스턴스를 만든다. 오버라이드 가능한 기본 함수 기능이 상당량 들어있다. 흔히 쓰이는 함수는 다음과 같다.
- InitGame : InitGame이벤트는 PreInitializeComponents
- PreLogin : 서버에 접근 시도중인 플레이어를 수락 또는 거부합니다. PreLogin은 Login 전 호출되며, 플레이어가 게임 콘텐츠를 다운로드해야 하는 경우 시간이 한참 지나서야 Login이 호출될 수도 있다.
- PostLogin : 로그인 성공 이후 호출. PlayerController에서 리플리케이트 되는 함수 호출을 하기에 안전한 첫 번째 장소이다.
- HandleStartingNewPlayer : PostLogin또는 심리스 트래블 이후 호출되며, 블루프린트에서 덮어써서 새 플레이어에게 벌어지는 일을 변경할 수 있다. 기본적으로 플레이어에 대한 폰을 생성한다.
- RestartPlayer : 플레이어의 폰 스폰을 시작하기 위해 호출된다. 폰의 스폰 위치를 지정하고자 하는 경우 RestartPlayerAtPlayerStart와 RestartPlayerAtTransform 함수를 사용할 수 있다.
- SpawnDefaultPawnAtTransform : 플레이어의 폰이 실제 스폰되는 곳으로, 블루프린트에서 덮어쓸 수 있다.
- Logout : 플레이어가 게임을 떠나거나 소멸되었을 때 호출된다.
class AGameMode
AGameModeBase의 서브 클래스로, 멀티플레이어 경기 및 기존 작동방식 지원을 위한 부가 함수가 몇 가지 들어있다. 새롭게 생성되는 프로젝트는 모두 AGameModeBase를 기본 사용하지만, 그 부가 함수가 필요한 경우 AGameMode를 상속하도록 전환할 수 있다. 만약 AGameMode를 상속하는 경우, AGameState에서 게임 스테이트를 상속해야 한다. AGameMode에는 경기 또는 일반 게임플레이 흐름 상태를 기록하는 스테이트 머신이 들어있는데, 현재 상태를 질의하기 위해서는 GetMatchState또는 HasMatchStarted, IsMatchInProgress, HasMatchEnded와 같은 Wrapper를 사용하면 된다.
가능한 경기 상태는 다음과 같다.
EnteringMap : 초기 상태이다. 액터 틱은 이루어지지 않고, 월드는 제대로 초기화되지 않은 상태이다. 모두 완전히 로드되면 다음 상태로 전환될 것이다.
WaitingToStart : 그 다음 상태로, 여기에 들어갈 때 HandleMatchIsWaitingToStart가 호출된다. 액터 틱은 이루어지지만, 플레이어는 아직 스폰되어 있지 않다. ReadyToStartMatch가 true를 반환하는 경우, StartMatch가 호출된 경우 다음 상태로 전환된다.
InProgress : 게임의 주요 부분이 일어나는 상태. 여기에 들어갈 때 HandleMatchHasStarted가 호출되며, 그 후 모든 액터에서 BeginPlay를 호출한다. 이 시점에서 일반적인 게임플레이가 진행된다. ReadyToEndMatch가 true를 반환하거나 EndMatch가 호출되는 경우 경기가 다음 상태로 전환된다.
WaitingPostMatch : 끝에서 두 번째 상태로, 여기에 들어갈 때 HandleMatchHasEnded가 호출된다. 액터 틱은 여전히 일어나지만 새로운 플레이어는 참가할 수 없다.
LeavingMap : 일반적인 흐름의 마지막 상태로, 여기에 들어설 때 HandleLeavingMap를 호출합니다. 경기가 이 상태에 머물러있다가 맵 전환이 일어나면 EnteringMap상태로 돌아간다.
Aborted : 실패상태로, AbortMatch를 호출하면 시작된다. 복구할 수 없는 오류가 발생했을 때 설정된다.
게임 모드 설정
레벨의 GameMode설정을 위한 메서드는 여러가지 있다. 우선권이 가장 낮은 것에서부터 차례대로 나열해 보겠다.
1. DefultEngine.ini파일의 /Script/EngineSettings.GameMapsSettings 섹션에 GlobalDefaultGameMode 항목으로 설정해 주면 프로젝트의 모든 맵에 대한 기본 게임 모드를 설정한다.
[/Script/EngineSettings.GameMapsSettings]
GlobalDefaultGameMode="/Script/MyGame.MyGameGameMode"
GlobalDefaultServerGameMode="/Script/MyGame.MyGameGameMode"
2. 개별 맵에 대해 프로젝트 세팅을 덮어쓰려면, 에디터에서 WorldSettings의 DefualtGameMode를 설정한다.
3. URL을 실행파일에 붙여 게임 시작시 로드할 맵을 강제 지정할 수 있다. game옵션을 사용하여 게임 모드를 설정할 수 있다. 자세한 내용은 https://docs.unrealengine.com/4.27/ko/ProductionPipelines/CommandLineArguments/
를 참고하자.
UE4Editor.exe /Game/Maps/MyMap?game=MyGameMode -game
4. 마지막으로 DefaultEngine.ini 파일의 /Script/Engine.WorldSettings/ 섹션에 맵 접두사(와 URL 메서드에 대한 앨리어스)를 설정할 수 있다. 이 접두사는 접두사가 붙은 모든 맵에 대한 기본 게임 모드를 설정한다.
[/Script/EngineSettings.GameMapsSettings]
+GameModeMapPrefixes=(Name="DM",GameMode="/Script/UnrealTournament.UTDMGameMode")
+GameModeClassAliases=(Name="DM",GameMode="/Script/UnrealTournament.UTDMGameMode")
GameState
접속된 플레이어 목록, 점수, 체스 게임에서 말들의 위치, 오픈 월드 게임에서 완료한 퀘스트 목록과 같은 것을 가지는 게임 상태가 포함된다. GameState는 서버와 모든 클라이언트에 존재하며, 최신 상태 유지를 위해 자유롭게 리플리케이트 가능하다. 게임에 규칙 관련 이벤트가 발생하고 트래킹을 통해 모든 플레이어와 공유할 필요가 있을 때, 그 정보는 게임 스테이트에 보관되고 이를 통해 동기화된다. 이번에도 간단한 예를 들어보자.
- 게임 실행 기간
- 각 플레이어의 게임 참가 기간, 그 플레이어의 현재 상태.
- 현재 게임 모드의 베이스 클래스.
- 게임 시작 여부.
개념적으로 게임 스테이트는 접속된 모든 클라이언트가 알아야 하는 정보, 플레이어 개개인이 아닌 게임 모드에 관련된 정보를 관리해야 한다. 그래서 접속된 플레이어 목록, 깃발 뺏기 게임의 팀 점수, 오픈 월드 게임에서 완료한 미션 등과 같은 전반적인 게임 프로퍼티 기록을 유지할 수 있다. GameState는 깃발 뺏기 게임에서 특정 플레이어가 팀 점수를 몇 점이나 올렸는가 와 같은 개별 플레이어 단위의 기록을 유지하기에 좋은 곳은 아니다. 그런 부분은 PlayerState에서 보다 깔끔하게 처리할 수 있기 때문이다. 일반적으로 게임 스테이트는 게임플레이 도중 변하면서 모두에게 관련이 있고 보일 수 있는 프로퍼티 기록을 유지해야 한다.
AGameStateBase는 게임에서 무슨 일이 벌어지고 있는지 플레이어에게 지속적으로 알리기 위해 필요한 변수와 함수를 넣기 위해 C++, 블루프린트로 자주 확장시키는 클래스이다.
PlayerState
인간 플레이어 또는 플레이어인 척 하는 봇과 같은 게임 참여자의 상태를 말한다. 게임의 일부로써 존재하는 플레이어가 아닌 AI에는 PlayerState가 없다. 예제를 하나 주자면, 플레이어 이름, 점수, MOBA 게임류에서의 대전상대 레벨, 플레이어가 현재 깃발을 운반중인지 여부 등이 PlayerState에 들어간다. PlayerController와는 달리 PlayerState는 모든 머신에 존재하며, 동기화 상태 유지를 위해 자유로이 리플리케이트 가능하다.
PlayerController와 AIController
PlayerController는 플레이어의 셋업이 이루어지는 곳이다. PlayerController는 Pawn에 빙의(Possess)되어 Pawn의 동작에 대한 규칙을 설정할 수 있다. 물론 Pawn 자체에 이동이나 기타 게임 로직용 규칙을 포함시킬 수 있다.
AIController는 말 그대로 Pawn을 제어하는 의지를 시뮬레이션으로 재현한 것이다.
Camera
PlayerCameraManager는 플레이어의 "눈"을 나타내며, 그 동작을 관리한다. 각 PlayerController에는 보통 하나씩 있다. Camera에 제공되는 시야는 사람 플레이어에게만 의미가 있으므로, 자신이 조종하는 Pawn에 있는 CameraComponent가 PlayerCamera에 사용된다.
Pawn과 Character
캐릭터는 인간형 폰이다. 기본적으로 콜리전에 쓸 CapsuleConponent와 CharacterMovementComponent가 들어있으며 기본적인 인간형 동작을 할 수 있다. 네트워크를 통해 부드러운 이동 리플리케이션이 가능하고, 애니메이션 관련 함수도 약간 있다.
HUD
Heads-Up Display의 준말이며, 여러 게임에서 볼 수 있는 머리 위에 뜨는 화면 표시기 같은 것으로, HP, 탄환 수, 총 조준선 등이 표시된다. 각 PlayerController에는 보통 이와 같은 것이 하나씩 있다.
< 프레임워크 클래스들 사이의 관계 >
이 흐름도는 위에서 설명한 코어 게임플레이 클래스끼리의 상관 관계를 나타낸다. 게임은 GameMode와 GameState로 이루어지고, 플레이어는 PlayerController에 연관된다. 이러한 PlayerController는 플레이어가 레벨 내 물리적 존재를 가질 수 있도록 Pawn에 빙의된다. PlayerController는 플레이어에게 입력 컨트롤, HUD, 카메라 시야처리를 제공한다.
게임 실행 프로세스 (에디터 방법 vs 독립형 방법)
독립형 : 에디터 외부에서 플레이하는 게임 모드로, 시작 시 엔진 초기화에 이어 게임 플레이에 필요한 오브젝트가 생성 및 초기화된다. GameInstance와 같은 오브젝트는 엔진 시작 전 생성 및 초기화되며, 엔진의 시작 함수 호출 직후 시작맵이 로드된다. 공식적으로 게임플레이가 시작되는 시점은 게임모드와 게임 스테이트에 이어 다른 액터를 생성한 이후이다.
에디터 : 에디터에서 플레이와 시뮬레이트에서 사용되며, 엔진은 에디터 실행에 필요하므로 즉시 초기화 및 시작되나, GameInstance와 같은 오브젝트의 생성 및 초기화는 사용자가 버튼을 눌러 실행할 때까지 연기된다. GameInstance를 포함한 모든 오브젝트는 각 PIE(Play In Editor)인스턴스마다 별도의 사본을 갖는다. UWorld클래스의 게임플레이 시작과 함께 에디터 방법과 독립형 방법의 재회가 이루어진다.
'UE4' 카테고리의 다른 글
[UE4] 언리얼 ui 최적화 기법 (4) | 2023.02.21 |
---|---|
[UE4] Projectile Movement Component (0) | 2023.02.14 |
[UE4] 캐릭터 무브먼트 컴포넌트 (0) | 2022.11.24 |
[UE4] 위젯 UI 제작하기 (0) | 2022.11.14 |
[UE4] UPROPERTY (0) | 2022.11.12 |