- GameMode는 게임의 전반적인 규칙과 흐름을 총괄 관리하는, 일종의 컨트롤러 타워 역할을 하는 클래스이다. - 싱글 플레이에서는 '서버' 와 '클라이언트' 개념이 나뉘지 않으므로, GameMode가 온전히 로컬에서 동작하여 게임 전체를 제어한다. - 어떤 Pawn (또는 Character)을 플레이어에게 스폰해줄지, 어떤 PlayerController를 사용할지, 승패 조건이나 점수 계산 방법은 어떻게 설정할지 등 게임 플레이의 핵심 로직을 담당한다. : 프로젝트 전역(기본) 혹은 레벨별로 필요한 GameMode를 구분해 설정할 수 있다. 예) 튜토리얼 맵 전용 GameMode, 일반 맵 전용 GameMode 등
- GameMode의 주요 기능과 책임
- 플레이어 Pawn/Character 스폰 : 게임이 시작될 때 (또는 플레이어가 리스폰 될 때), DefaultPawnClass 또는 지정한 Pawn 클래스를 자동으로 스폰한다. 스폰된 Pawn을 플레이어가 조작할 수 있도록, PlayerController와 연동해주는 역할을 한다. - PlayerController 지정 : 플레이어의 입력 (키보드, 마우스, 게임패드 등)을 전달하고 처리하는 PlayerController가 어떤 클래스로 동작할지 설정한다. - 게임 규칙 관리 : 점수 계산, 타이머, 라운드 제어, 난이도 등 게임 전반의 규칙을 정의하고 유지한다. 특정 점수 달성, 보스 몬스터 처치, 제한 시간 종료 등 승리/패배를 결정하는 조건을 관리한다. 승리 혹은 패배가 확정되면, 게임 오버 화면을 띄우거나 다음 레벨로 전환하는 식의 후속 처리를 담당한다. - GameState / PlayerState 사용 : GameState는 전체 게임 흐름 (타이머, 전역 변수 등), PlayerState는 플레이어별 정보 (체력, 점수 등)를 관리하는 용도로 쓰일 수 있다. 멀티플레이만큼 복잡하게 쓰진 않더라도, 상태 저장과 관리를 좀 더 체계적으로 하고 싶을 때 유용하다.
2. GameMode 클래스 생성하기
- GameMode vs GameModeBase
: 언리얼 엔진 5에는 GameMode와 GameModeBase 두 종류가 있다.
- GameMode : 언리얼에서 제공하는 멀티플레이 기능 (세션, 플레이어 연결 로직)을 일부 포함하고 있으며, 싱글 플레이에서도 문제없이 사용할 수 있다. 필요에 따라 GameState, PlayerState 등 연동이 활성화 되어 있다. - GameModeBase : 좀 더 단순화 된 형태로, 멀티플레이 관련 로직이 거의 포함되지 않는다. 간단한 싱글 플레이 게임 또는 직접 멀티플레이 로직을 구현하고 싶을 때 사용하기도 한다.
- C++ 클래스 GameMode 생성
- 언리얼 에디터 상단 메뉴에서 Tools -> New C++ Class를 클릭한다. - Common Classes 목록 또는 검색창에서 GameMode를 선택한다. - 클래스 접근 수준을 Public으로 설정한 후, 클래스 이름을 SpartaGameMode로 지정하고 CreateClass 버튼을 클릭한다. - 잠시 후 엔진이 프로젝트를 빌드하고, Visual Studio에서 SpartaGameMode.h 와 SpartaGameMode.cpp 파일을 자동으로 열어준다. - 코드를 열어 보면 SpartaGameMode클래스가 GameMode를 상속받고 있으며, 아직 아무런 로직이 구현되지 않은 기본 골격만 갖추고 있다.
- GameMode 클래스 적용
: 직접 만든 C++ GameMode 클래스를 게임에서 활용하려면, 일반적으로 블루프린트 클래스로 한 번 더 감싸는 방식을 권장한다.
이렇게 하면, 에디터에서 세부 파라미터를 수정하기 훨씬 편리하기 때문이다.
- Content Browser에서 SpartaGameMode를 우클릭하고, Create Blueprint Class based on SpartaGameMode를 선택한다. - 이름은 BP_SpartaGameMode로 지정하고, Blueprints 폴더에 생성한다.
- 언리얼 엔진에서 GameMode를 적용하는 방법은 크게 2가지이다.
1) 프로젝트 전역 설정
- 상단 메뉴 Edit -> Project Settings로 이동 -> 왼쪽 목록에서 Maps & Modes 항목 선택 - Default GameMode 를 BP_SpartaGameMode로 지정 - 이 프로젝트의 모든 레벨에 대해 기본 GameMode가 BP_SpartaGameMode가 된다.
2) 레벨 별 설정
- 상단 메뉴 Window -> World Settings를 클릭해 World Settings 창을 연다.
- 현재 열려 있는 레벨의 GameMode Override를 BP_SpartaGameMode로 지정
- 이렇게 하면, 이 특정 레벨은 프로젝트 전역 설정 대신BP_SprataGameMode를 사용하게 된다.
* 만약 프로젝트 전역 설정과 레벨 별 설정이 충돌한다면, 레벨 별 설정 (World Settings)이 우선 적용된다.
즉, 레벨에서 오버라이드 된 GameMode가 존재한다면 그 레벨에서는 해당 GameMode를 사용하고, 그렇지 않은 레벨은 전역에 설정된 GameMode를 사용한다.
- 게임 모드 기본 설정 확인
: 현재 BP_SpartaGameMode에는 별도의 코드나 설정이 없으므로, 언리얼 엔진의 기본값이 적용된다.
World Settings 창의 'Selected GameMode' 영역을 펼쳐보면 다음과 같은 기본 클래스를 확인 할 수 있다.
- Default Pawn Class : 레벨 시작 시 플레이어가 조종하게 될 Pawn(또는 Character) 클래스를 지정한다. - HUD Class : 게임 화면에 표시되는 HUD(UI) 요소를 관리하는 클래스를 지정한다. - Player Controller Class :플레이어 입력 처리와 카메라 제어, UI와의 상호작용을 담당하는 클래스를 지정한다. - Game State Class / Player State Class :게임의 전역 상태나 플레이어별 상태를 추적할 때 사용한다. - Spectator Class :관전자 모드에서 사용할 Pawn 클래스를 지정한다. 일반 플레이어와 다른 이동 방식이나 카메라 제어가 필요할 때 활용한다.
3. Pawn과 Character 클래스 이해하기
- Pawn 클래스란?
- Pawn은 플레이어 혹은 AI가 "소유 (Possess)" 할 수 있는 가장 상위 클래스이다. 즉 엔진에서 "무언가를 조종한다" 라고 할 때 기본이 되는 형태가 Pawn이 된다. - Pawn에는 이동 로직이나 충돌 처리, 중력, 네트워크 이동을 위한 기능들이 기본적으로 포함되어 있지 않다. - 보행(걷기, 달리기, 점프 등)에 필요한 시스템(캡슐 콜리전, 중력, 지형 따라가기)을 모든 단계에서 직접 구현해야 하므로, 사람 캐릭터를 처음부터 Pawn으로 만들기에는 다소 부담이 크다. - 이러한 특성 덕분에, 비행기, 드론, 카메라처럼 기존 Character의 이동 방식을 벗어난 특수한 로직을 완전히 자유롭게 구현할 때 유용하다.
- Character 클래스란?
- Character는 Pawn을 상속 받아 만들어진 자식 클래스 중 하나로, 기본적으로 UChracterMovementComponent를 포함하고 있다. - 이동, 회전, 점프, 중력, 지형 따라가기, 네트워크 동기화 등보행형 캐릭터에게 필요한 기능이 이미 구현되어 있어, 사람이 달리고 점프하는 형태의 캐릭터를 쉽게 만들 수 있다. - 여기에 미리 정의된 대표적인 함수들(에: MoveForward, MoveRight, Jump)이 존재하므로, 몇 줄의 모드만 추가해도 금방 캐릭터 움직임을 테스트 할 수 있다. - 캐릭터를 구성하는 전형적인 요소들이 표준화되어 있어, 일반적인 인간형 캐릭터를 만드는 데 최적화되어 있다. - 단, 자동차나 비행기처럼 완전히 다른 이동 방식을 구현할 때는 Character 내부에 탑재된 기능들이 오히려 방해가 될 수 있다. 이런 경우에는 Pawn을 직접 확장해서 사용하는 것을 고려해야 한다.
- Character 클래스 생성
- 언리얼 에디터 상단 메뉴에서 Tools -> New C++ Class를 클릭한다. - 부모 클래스로 Character를 선택한다. - 클래스 이름은 SpartaCharacter로, Public 접근 지정자로 설정한 뒤 Create Class를 클릭한다. - C++ 클래스가 생성되면 Contetnt Browser에서 C++ Classes 폴더 내의 SpartaCharacter 클래스를 우클릭하여, Create Blueprint class based on SpartaCharacter를 선택한다. - 이름을 BP_SpartaCharacter로 지정하고, Blueprints 폴더에 저장한다.
- Chracter 클래스 구조 살펴보기
: BP_SpartaCharacter를 열면, 왼쪽 컴포넌트 트리에 이미 여러 기본 컴포넌트가 포함되어 있다.
1. CapsuleComponent (Root Component)
- 캐릭터가 벽이나 지형에 충돌하는 범위를 정의하는 콜리전 컴포넌트이다. - 캡슐 형태이며, Radius (반지름)와 Half Height (높이 절반)를 조정해 캐릭터의 물리적 크기를 설정할 수 있다. 2. ArrowComponent - 캐릭터가 어느 방향을 바라보고 있는지를 표시하기 위해 씬에 화살표를 띄워주는 컴포넌트이다. - 게임플레이 로직에는 직접적인 영향을 주지 않고, 주로 편집기에서 시각적 디버깅용으로 사용된다. 3. SkeletalMeshComponent - 캐릭터의 3D 모델과 애니메이션을 적용하는 컴포넌트이다. - Skeletal Mesh, Anim Blueprint 등을 여기로 할당해 캐릭터의 외형과 동작을 제어한다. 4. CharacterMovementComponent - 캐릭터의 이동, 점프, 중력, 네트워크 동기화 등 물리적 이동 로직을 담당하는 핵심 컴포넌트이다. - 언리얼에서 제공하는 주요 이동 함수 (MoveForward, MoveRight, Jump)가이미 연결되어 있어, 최소한의 코드만으로 캐릭터 조작을 구현할 수 있다.
5. 스켈레탈 메시 설정하기하기
- Skeleta Mesh란?
- Skeletal Mesh는 내부에 뼈대(Skeleton)를 갖춘 3D 모델을 의미한다. : 이 뼈대(본, Bone)가 부모-자식 관계로 연결되어 있으며, 본이 움직이면 외형 (Mesh)도 함께 움직이게 된다. 예 : 팔, 다리, 머리 등 신체 부위별 본이 존재한다. - 본과 메시가 연동되기 때문에, 애니메이션 (Bone 움직임)에 맞춰 캐릭터가 뛰거나 걷는 동작을 구현할 수 있다. - 언리얼 엔진은 물리 엔진과도 연결할 수 있어, Ragdoll(피격 후 쓰러지는) 효과 등 물리 기반 애니메이션도 쉽게 가능하다.
- 메시 위치 및 방향 조절
- 메시 방향 조정 - 언리얼에서 일반적으로 캐릭터의 전방 방향은 X축이다. - 그러나 SKM_Manny나 SKM_Quinn의 모델은 Y축을 전방으로 사용하기 때문에, 적용 후 캐릭터가 옆을 보는 것 처럼 보일 수 있다. - 이를 해결하려면 Mesh 컴포넌트 선택 후 Details 패널에서 Rotation -> Yaw(Z축) 값을 -90도로 조정한다.
- 캡슐 크기와 메시 위치 조정
- 언리얼의 Character 클래스는 최상위 루트로 CapsuleComponent(캡슐 형태 충돌체)를 사용한다. - 그 내부 중앙 부분에 Skeletal Mesh가 위치하게 된다. - BP_SpartaCharacter 뷰표트에서 Mesh 컴포넌트를 선택한 뒤, Location 값을 조정해 캐릭터의 발이 캡슐 바닥에 정확히 닿도록 위치를 맞춘다. - 캡슐 충돌 범위가 너무 작거나 크면 게임 플레이 시 충돌 문제가 발생할 수 있으므로, CapsuleComponent를 선택하고 Half Height, Radius 값을 적절히 조절한다.
6. 카메라 및 GameMode 설정하기
: 3인칭 게임에서는 플레이어가 캐릭터의 뒤쪽이나 어깨 너머 시점을 보며 이동하는 경우가 많다.
이를 위해 SpringArm과 CameraComponent를 추가한다.
이후 GameMode 설정을 통해, 만든 캐릭터가 스폰되도록 구성한다.
- SpringArm 및 CameraComponent 추가
: SpartaCharacter.h를 열고, 아래처럼 스프링 암(SpringArm)과 카메라(Camera) 관련 클래스를 전방 선언하고 프로퍼티를 추가한다.
- 이 코드가 있으면, 게임 시작 시 SpartaCharacter가 자동으로 스폰되고, PlayerController와 연결되어 플레이어가 조작할 수 있게 된다.
오늘 배운 것에서 개인적으로중요하다고생각하는 것
- Forward Declaration (전방 선언) : 전방 선언은 구체적인 내용(.h파일)을 통째로 들고 오는 대신, 이름표만 먼저 보여주는 것이다. (빌드 시간 획기적으로 단축) - bUsePawnControlRotation = true or false : "카메라(또는 스프링 암)의 회전을 플레이어의 입력(컨트롤러 회전)에 동기화 할 것인가?" 를 결정하는 것이다.