GameMode이해하기
1️⃣GameMode란?
- GameMode는 게임 전반적인 규칙과 흐름을 총괄 관리하는 일종의 컨트롤 타워 역할을 하는 클래스
- 싱글 플레이에선 '서버'와 '클라이언트' 개념이 나눠지지 않으므로, GameMode가 온전히 로컬에서 동작하여 게임 전체를 제어
- 어떤 Pawn(또는 Character)을 플레이어에게 스폰해줄지, 어떤 PlayerController를 사용할지, 승패 조건이나 점수 계산 방법은 어떻게 설정할지 등 게임 플레이의 핵심 로직을 담당함
- 프로젝트 전역(기본) 혹은 레벨별로 필요한 GameMode를 구분해 설정 가능
2️⃣GameMode의 주요 기능과 책임
- 플레이어 Pawn/Character Spawn
- 게임이 시작될 때(또는 플레이어가 리스폰될 때), DefaultPawnClass 또는 지정한 Pwn 클래스를 자동으로 Spawn
- Spawn된 Pawn을 플레이어가 조작할 수 있도록 PlayerController와 연동해주는 역할을 함
- PlayerContreoller 지정
- 플레이어의 입력(키보드, 마우스, 게임패드 등)을 전달하고 처리하는 PlayerController가 어떤 클래스로 동작할 지 설정
- 게임 규칙 관리
- 점수 계산, 타이머, 라운드 제어, 난이도 등 게임 전반의 규칙을 정의하고 유지
- 특정 점수 달성, 보스 몬스터 처치, 제하느시간 종료 등 승리/패배를 결정하는 조건을 관리
- 승리/패배가 확정되면 게임 오버 화면을 띄우거나 다음 레벨로 전환하는 식의 후속 처리를 담당
- GameState/PlayerState 사용
- GameState는 전체 게임 흐름(타이머, 전역 변수 등), PlayerState는 플레이어별 정보(체력, 점수 등)를 관리하는 용도로 쓰일 수 있음
- 멀티플레이만큼 복잡하게 쓰진 않더라도, 상태 저장과 관리를 좀 더 체계적으로 하고 싶을 때 유용
GameMode 클래스 생성
1️⃣GameMode VS GameModeBase
- GameMode
- 언리얼에서 제공하는 멀티플레이 기능을 일부 포함하고, 싱글 플레이도 문제없이 사용 가능
- 필요에 따라 GameState, PlayerState등 연동이 활성화 되어있음
- GameModeBase
- 좀 더 단순화된 형태로, 멀티 플레이 관련 로직이 거의 포함되어있지 않음
- 간단한 싱글 플레이 게임 또는 직접 멀티플레이 로직을 구현하고 싶을 때 사용
2️⃣GameMode 생성 및 적용
- GameMode Class를 생성해주고 클래스를 확인해보자
- 아직은 아무런 것도 없을 것이다
- 현재 Character가 없기 때문에 나중에 사용하기로 하고 적용을 시켜보기 위해 블루프린트로 만들어보자
- 적용하는 방법은 크게 두가지이다
- 프로젝트 전역 설정
- Default GameMode를 우리가 만든 BP 클래스로 바꾸기
- 레벨별 설정
- 현재 열려있는 레벨의 GameModeOverride를 BP 로 지정
- 이렇게 하면 이 특정 레벨은 프로젝트 전역 설정 대신 BP를 사용하게 됨
- 현재 열려있는 레벨의 GameModeOverride를 BP 로 지정
- 프로젝트 전역 설정
- 만약 프로젝트 전역 설정과 레벨별 설정이 충돌한다면, 레벨별 설정이 우선 적용됨
3️⃣GameMode 기본 설정 확인
- WorldSettings에 GameMode를 살펴보자
- DefaultPawn Class : 레벨 시작 시 플레이어가 조종하게 될 Pawn(또는 Character) 클래스를 지정
- HUD Class : 게임 화면에 표시되는 HUD(UI) 요소를 관리하는 클래스를 지정
- Player Controller Class : 플레이어 입력 처리와 카메라 제어, UI와의 상호작용을 담당하는 클래스를 지정
- GameState Class/Player State Class : 플레이어 입력 처리와 카메라 제어, UI 와의 상호작용을 담당하는 클래스 지정
- Spectator Class : 관전 모드에서 사용할 Pawn Class를 지정함, 일반 플레이어와 다른 이동 방식이나 카메라 제어가 필요할 때 활용
Pawn과 Chartacter 클래스 이해하기
1️⃣Pawn Class란?
- Pawn은 플레이어 혹은 AI가 "소유(Possess)" 할 수 있는 가장 상위 클래스
- 엔진에서 무언가를 조종한다 할 때 기본 형태가 Pawn이 됨
- Pawn은 이동, 충돌, 중력, 네트워크 이동을 위한 기능이 포함되어 있지 않음
- 보행(걷기, 달리기, 점프 등)에 필요한 시스템(캡슐 콜리전, 중력, 지형 따라가기)을 모든 단계에서 직접 구현해야 하므로, 사람 캐릭터를 처음부터 Pawn으로 만들기에는 부담이 큼
- 이러한 특성 때문에 비행기, 드론, 카메라처럼 기존 Character의 이동 방식을 벗어난 특수한 로직을 완전 자유롭게 구현할 때 유용
2️⃣Character Class 란?
- Character는 Pawn을 상속받아 만들어진 자식 클래스 중 하나로, 기본적으로 UCharacterMovementComponent를 포함하고 있음
- 이동, 회전, 점프, 중력, 지형 따라가기, 네트워크 동기화 등 보행형 캐릭터에게 필요한 기능이 이미 구현되어 있어, 사람이 달리고 점프하는 형태의 캐릭터를 쉽게 만들 수 있음
- 여기 미리 정의된 대표적인 함수들이 존재하므로, 몇 줄의 코드만으로 금방 캐릭터의 움직임을 구현 가능
- 캐릭터를 구성하는 전형적인 요소들이 표준화되어 있어, 일반적인 인간형 캐릭터를 만드는ㄴ데 최적화되어 있음
- 자동차나 비행기처럼 완전 다른 이동 방식을 구현할 땐 Character 내부에 탑재된 기능이 방해될 수 있어 Pawn을 상속받아 직접 구현하는 것을 고려해야함
Character Class 생성
1️⃣생성
- Character Class를 상속받아 생성 후 확인해보면 여러 함수가 구현되어 있는 것을 볼 수 있다
2️⃣구조 살펴보기
- 만들어진 Class를 BP를 만들어 확인해보면 왼쪽 컴포넌트 트리에 이미 여러개의 컴포넌트가 포함된 것을 볼 수 있다
- CapsuleComponent(Root Component)
- 캐릭터가 벽이나 지형에 충돌하는 범위를 정의하는 콜리전 컴포넌트
- 캡슐 형태이며, Radius와 HalfHeight를 조정해 캐릭터의 물리적 크기를 설정 가능
- ArrowComponent
- 캐릭터가 어느 방향을 바라보고 있는지 표시하기 위한 씬에 화살표를 띄어주는 컴포넌트
- 게임 플레이 로직에는 직접 영향을 주지 않고, 주로 편집기에 시각적 디버깅용으로 사용
- SkeletalMeshComponent
- 캐릭터의 3D 모델과 애니메이션을 적용하는 컴포넌트
- Skeletal Mesh, Anim Blueprint등을 여기로 할당해 캐릭터의 외형과 동작을 제어
- CharacterMovementCOmponent
- 캐릭터의 이동, 점프, 중력, 네트워크 동기화등 물리적 이동 로직을 담당하는 핵심 컴포넌트
- 언리얼에서 제공하는 주요 이동 함수가 이미 연결되어있어 최소한의 코드만으로 캐릭터 조작을 구현할 수 있음
- CapsuleComponent(Root Component)
Skeletal Mesh 설정
1️⃣Skeletal Mesh 설정
- Skeletal Mesh란?
- 내부에 뼈대(Skeleton)를 갖춘 3D 모델
- 이 뼈대는 부모-자식 관계로 연겨로디어 있어, 본이 움직이면 외형도 움직임
- 본과 Mesh가 연동되어 있어, 애니메이션에 맞춰 캐릭터가 뛰거나 걷는 동작을 구현할 수 있음
- 언리얼 엔진은 물리 엔진과도 연결 가능해 Ragdoll 효과 등 물리기반 애니메이션 구현도 쉽게 가능
- 내부에 뼈대(Skeleton)를 갖춘 3D 모델
- SkeletalMesh 설정
- Character BP에 컴포넌트 트리에 Mesh 컴포넌트를 선택한 후 우측 Details 패널에 Skeletal Mesh 항목에 Mesh 할당
- Character BP에 컴포넌트 트리에 Mesh 컴포넌트를 선택한 후 우측 Details 패널에 Skeletal Mesh 항목에 Mesh 할당
2️⃣메시 위치 및 방향 조정
- 메시 방향 조정
- 언리얼에선 캐릭터의 전방 방향은 X축임
- 그러나 모델에 따라 Y축을 전방으로 사용하기 때문에 옆을 보는 것 처럼 보일 수 있음
- 이를 해결하기 위해 Mesh Component 선택 후 우측 Details 패널에 Rotation을 변경하면 됨
- 캡슐 크기와 메쉬 위치 조정
- Character Class는 최상위 루트로 CapsuleComponent를 사용함
- 그 내부 중앙에 SkeletalMesh가 위치하게 하기위해 Mesh의 발이 캡슐의 바닥에 정확히 일치하게 해야함
- 캡슐의 충돌 범위가 작으면 충돌에 문제가 발생할 수 있으므로 CapsuleComponent의 Half Height, Radius 값을 조절하면 됨
- 코드로 변경
- ACharacter Class에 이미 구현된 Mesh Class는 private으로 되어있기 때문에 직접 가져다 쓰진 못하지만 내부에 Getter 함수가 구현되어 있어 그 함수를 이용하면 된다
ACCharacter::ACCharacter()
{
PrimaryActorTick.bCanEverTick = true;
static ConstructorHelpers::FObjectFinder<USkeletalMesh> asset(L"/Script/Engine.SkeletalMesh'/Game/Resources/Characters/Meshes/SKM_Manny.SKM_Manny'");
if (asset.Succeeded() == true)
GetMesh()->SetSkeletalMesh(asset.Object);
GetMesh()->SetRelativeRotation(FRotator(0.0f, -90.0f, 0.0f));
GetMesh()->SetRelativeLocation(FVector(0.0f, 0.0f, -90.0f));
}
카메라 및 GameMode 설정
- 3인칭 게임이선 플레이어가 캐릭터의 뒷쪽이나 어깨 너머 시점을 보며 이동하는 경우가 많아 이를 구현하기 위해 SpringArm, CameraComponent를 추가 후 GmaMode 설정을 통해 우리가 만든 캐릭터가 기본으로 Spawn되도록 만들어 볼 것이다
1️⃣SpringArm 및 CameraComponent 추가
class UCameraComponent;
class USpringArmComponent;
UCLASS()
class SPARTAPROJECT_API ACCharacter : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
ACCharacter();
public:
UPROPERTY(EditAnywhere, BlueprintReadOnly)
USpringArmComponent* SpringArm;
UPROPERTY(EditAnywhere, BlueprintReadOnly)
UCameraComponent* Camera;
};
.cpp
ACCharacter::ACCharacter()
{
//SprintArm Setting
{
SpringArm = CreateDefaultSubobject<USpringArmComponent>("SpringArm");
SpringArm->SetupAttachment(RootComponent);
SpringArm->TargetArmLength = 300.0f;
SpringArm->SetRelativeLocation(FVector(0.0f, 0.0f, 50.0f));
SpringArm->bUsePawnControlRotation = true;
}
//Camera setting
{
Camera = CreateDefaultSubobject<UCameraComponent>("Camera");
Camera->SetupAttachment(SpringArm, USpringArmComponent::SocketName);
Camera->bUsePawnControlRotation = false;
}
//Mesh 설정
{
static ConstructorHelpers::FObjectFinder<USkeletalMesh> asset(L"/Script/Engine.SkeletalMesh'/Game/Resources/Characters/Meshes/SKM_Manny.SKM_Manny'");
if (asset.Succeeded() == true)
GetMesh()->SetSkeletalMesh(asset.Object);
GetMesh()->SetRelativeRotation(FRotator(0.0f, -90.0f, 0.0f));
GetMesh()->SetRelativeLocation(FVector(0.0f, 0.0f, -90.0f));
}
}
- VisibleAnywhere, BlueprintReadOnly: 블루프린트에서 보기만 가능하고, C++ 코드에서 수정 가능하게 만드는 속성
- ForwardDeclaration(전방선언) : 헤더 파일의 의존성을 줄이는 방법
- SpringArmComponent
- SpringArmComponent(카메라 붐)
- 캐릭터와 카메라 간의 거리를 유지하고 충돌시 카메라가 벽등에 박히지 않도록 위치를 자동 조정
- CameraComponent
- 실제 화면에 표시되는 카메라 컴포넌트
- 위치와 회전을 제어하면 게임 뷰가 변경됨
- bUsePawnControlRotation
- 플레이어가 회전하면 Controller의 회전 값이 변경되어 이를 따라 자연스럽게 회전을 할지 말지를 결정하도록 하는 bool형 변수
- 문제가 없다면 컴포넌트 트리와 Viewport에 적용이 잘 된것을 볼 수 있다
2️⃣GameMode에서 DefaultPawn Class 설정
- DefaultPawnClass는 "게임 시작 시 어떤 캐릭터(Pawn)를 플레이어에게 제공할지 결정하는 것
UCLASS()
class SPARTAPROJECT_API ACGameMode : public AGameMode
{
GENERATED_BODY()
public:
ACGameMode();
};
.cpp
ACGameMode::ACGameMode()
{
DefaultPawnClass = ACCharacter::StaticClass();
}
- StaticClass : 객체 인스턴스를 사용하지 않고 클래스 자체의 정보를 다룰 수 있게 해주며, 주로 동적 객체 생성이나 타입 체크에 사용됨
- 이렇게 하면 게임 시작 시 Character가 자동 Spawn되고 PlayerController와 연결되어 플레이어가 조작할 수 있게 됨
4️⃣구현 테스트
'Unreal Bootcamp > Unreal C++' 카테고리의 다른 글
10.캐릭터 동작 구현과 입력 처리 (0) | 2025.01.31 |
---|---|
9. Enhanced Input System을 활용한 입력 매핑 (0) | 2025.01.23 |
7. 리플렉션 시스템 (0) | 2025.01.22 |
6. Tick 함수로 Actor의 Transform 조정 (0) | 2025.01.22 |
5. Actor의 라이프 사이클 (0) | 2025.01.21 |