게임 어떤 클래스를 만들겠다는 건 게임모드라는 클래스를 상속받는 클래스를 만들겠다는 얘기임

GameMode란?

  • GameMode는 게임의 전반적인 규칙과 흐름을 총괄 관리하는, 일종의 컨트롤 타워 역할을 하는 클래스
  • 싱글 플레이에서는 서버와 클라이언트 개념이 나뉘지 않으므로, GameMode가 온전히 로컬에서 동작하여 게임 전체를 제어함
  • 어떤 Pawn (또는 Character)을 플레이어에게 스폰해줄지, 어떤 PlayerController를 사용할지, 승패 조건이나 점수 계산 방법은 어떻게 설정할지 등 게임 플레이의 핵심 로직을 담당
    • 프로젝트 전역(기본) 혹은 레벨별로 필요한 GameMode를 구분해 설정할 수 있음. (예: 튜토리얼 맵 전용 GameMode, 일반 맵 전용 GameMode 등)

GameMode의 주요 기능과 책임

  • 플레이어 Pawn/Character 스폰
    • 게임이 시작될 때 (또는 플레이어가 리스폰될 때), DefaultPawnClass 또는 지정한 Pawn 클래스를 자동으로 스폰
    • 스폰된 Pawn을 플레이어가 조작할 수 있도록 PlayerController와 연동해주는 역할
  • PlayerController 지정
    • 플레이어의 입력(키보드, 마우스, 게임패드 등)을 전달하고 처리하는 PlayerController가 어떤 클래스로 동작할지 설정
  • 게임 규칙 관리
    • 점수 계산, 타이머, 라운드 제어, 난이도 등 게임 전반의 규칙을 정의하고 유지
    • 특정 점수 달성, 보스 몬스터 처치, 제한 시간 종료 등 승리/패배를 결정하는 조건을 관리
    • 승리 혹은 패배가 확정되면, 게임 오버 화면을 띄우거나 다음 레벨로 전환하는 식의 후속 처리를 담당
  • GameState / PlayerState 사용
    • GameState는 전체 게임 흐름 (타이머, 전역 변수 등), PlayerState는 플레이어별 정보 (체력, 점수 등)를 관리하는 용도로 쓰일 수 있음
    • 멀티플레이만큼 복잡하게 쓰진 않더라도, 상태 저장과 관리를 좀 더 체계적으로 하고 싶을 때 유용

<GameMode 클래스 생성하기>

GameMode vs GameModeBase

  • GameMode
    • 언리얼에서 제공하는 멀티플레이 기능 (세션, 플레이어 연결 로직 등)을 일부 포함하고 있으며, 싱글 플레이에서도 문제없이 사용할 수 있습니다.
    • 필요에 따라 GameState, PlayerState 등 연동이 활성화되어 있습니다
  • GameModeBase
    • 좀 더 단순화된 형태로, 멀티플레이 관련 로직이 거의 포함되지 않습니다.
    • 간단한 싱글 플레이 게임 또는 직접 멀티플레이 로직을 구현하고 싶을 때 사용하기도 합니다.

 

1. tools -> new c++ class -> gamemode 지정하고 클래스 접근 수준을 Public으로 설정한 후, 클래스 이름을 원하는 대로 지정하고 Create Class 버튼을 클릭

 

2. 블루프린트에 상속받기

-> 직접 만든 C++ GameMode 클래스를 게임에서 활용하려면 일반적으로 블루프린트 클래스로 한 번 더 감싸는 방식을 권장함(에디터에서 세부 파라미터를 수정하기 훨씬 편리하기 때문)

  • Content Browser에서 gamemode를 우클릭하고, Create Blueprint Class based on 게임모드 클래스 이름을 선택
  • 앞에 BP_게임모드 클래스 이름 붙여서 이름 만들고 생성

 

블루프린트 오른쪽 위쪽을 보면 어디를 상속하고 있는지 알 수 있음.

 

3. 총괄관리자인 gamemode를 레벨에 적용하기

 

<전역게임모드지정>

edit -> project setting -> maps&modes

Default GameMode를 만들어놓은 BP_게임모드 클래스 이름로 변경

-> 이 프로젝트의 모든 레벨에 대해 기본 GameMode가 BP_게임모드 클래스 이름으로 변경됨.

게임모드가 관리하는 클래스들 확인 가능

 

<레벨 하나에다만 지정하고 싶을 때>

window -> world settings ->   

 

현재 열려 있는 레벨의 GameMode Override를 BP_게임모드 클래스 이름으로 변경

-> 이렇게 하면, 이 특정 레벨은 프로젝트 전역 설정 대신 BP_게임모드 클래스 이름을 사용하게 됨

 

우선순위 : 레벨에 지정된 game mode가 1순위가 됨. 2순위가 전역에서 지정한 것

 


Pawn 클래스란?

  • Pawn은 플레이어 혹은 AI가 “소유( Possess )”할 수 있는 가장 상위 클래스입니다. 즉, 엔진에서 “무언가를 조종한다”라고 할 때 기본이 되는 형태가 Pawn이 됩니다.
  • Pawn에는 이동 로직이나 충돌 처리, 중력, 네트워크 이동을 위한 기능들이 기본적으로 포함되어 있지 않습니다.
    • 보행 (걷기, 달리기, 점프 등)에 필요한 시스템 (캡슐 콜리전, 중력, 지형 따라가기)을 모든 단계에서 직접 구현해야 하므로, 사람 캐릭터를 처음부터 Pawn으로 만들기에는 다소 부담이 큽니다.
  • 이러한 특성 덕분에, 비행기, 드론, 카메라처럼 기존 Character의 이동 방식을 벗어난 특수한 로직을 완전히 자유롭게 구현할 때 유용합니다.

Character 클래스란?

  • Character는 Pawn을 상속받아 만들어진 자식 클래스 중 하나로, 기본적으로 UCharacterMovementComponent를 포함하고 있습니다.
    • 이동, 회전, 점프, 중력, 지형 따라가기, 네트워크 동기화보행형 캐릭터에게 필요한 기능이 이미 구현되어 있어, 사람이 달리고 점프하는 형태의 캐릭터를 쉽게 만들 수 있습니다.
    • 여기에 미리 정의된 대표적인 함수들(예: MoveForward, MoveRight, Jump)이 존재하므로, 몇 줄의 코드만 추가해도 금방 캐릭터 움직임을 테스트할 수 있습니다.
  • 캐릭터를 구성하는 전형적인 요소들이 표준화되어 있어, 일반적인 인간형 캐릭터를 만드는 데 최적화되어 있습니다.
    • 단, 자동차비행기처럼 완전히 다른 이동 방식을 구현할 때는 Character 내부에 탑재된 기능들이 오히려 방해가 될 수 있습니다. 이런 경우에는 Pawn을 직접 확장해서 사용하는 것을 고려해야 합니다.

 

<Character 클래스 생성>

1. tool -> c++ -> character 생성 -> 부모 클래스로 character 선택 -> 캐릭터 클래스 이름 설정 -> public 접근 지정자로 설정한 뒤 create class

 

2. 블루프린트로 상속

  • C++ 클래스가 생성되면 Content Browser에서 C++ Classes 폴더 내의 SpartaCharacter 클래스를 우클릭하여 Create Blueprint class based on 캐릭터 클래스 이름을 선택합니다.
  • 이름을 BP_캐릭터 클래스 이름로 지정하고, Blueprints 폴더에 저장합니다.

 

 

 

블루프린트를 열면 왼쪽 컴포넌트 트리에 이미 여러 기본 컴포넌트가 포함되어 있는 걸 볼 수 있음.

 

1. CapsuleComponent (Root Component)

  • 캐릭터가 벽이나 지형에 충돌하는 범위를 정의하는 콜리전 컴포넌트입니다.
  • 캡슐 형태이며, Radius (반지름)와 Half Height (높이 절반)를 조정해 캐릭터의 물리적 크기를 설정할 수 있습니다.

2. ArrowComponent

  • 캐릭터가 어느 방향을 바라보고 있는지를 표시하기 위해 씬에 화살표를 띄워주는 컴포넌트입니다.
  • 게임플레이 로직에는 직접적인 영향을 주지 않고, 주로 편집기에서 시각적 디버깅용으로 사용됩니다.

3. SkeletalMeshComponent

  • 캐릭터의 3D 모델과 애니메이션을 적용하는 컴포넌트입니다.
  • Skeletal Mesh, Anim Blueprint 등을 여기로 할당해 캐릭터의 외형동작을 제어합니다.

4. CharacterMovementComponent

  • 캐릭터의 이동, 점프, 중력, 네트워크 동기화 등 물리적 이동 로직을 담당하는 핵심 컴포넌트입니다.
  • 언리얼에서 제공하는 주요 이동 함수 (MoveForward, MoveRight, Jump)가 이미 연결되어 있어, 최소한의 코드만으로 캐릭터 조작을 구현할 수 있습니다.

 

<스켈레탈 메시 설정>

  • Skeletal Mesh란?
    • Skeletal Mesh는 내부에 뼈대 (Skeleton)를 갖춘 3D 모델을 의미합니다.
      • 이 뼈대 (본, Bone)가 부모-자식 관계로 연결되어 있으며, 본이 움직이면 외형 (Mesh)도 함께 움직이게 됩니다.
      • 예: 팔, 다리, 머리 등 신체 부위별 본이 존재.
    • 본과 메시가 연동되기 때문에, 애니메이션 (Bone 움직임)에 맞춰 캐릭터가 뛰거나 걷는 동작을 구현할 수 있습니다.
    • 언리얼 엔진은 물리 엔진과도 연결할 수 있어, Ragdoll(피격 후 쓰러지는) 효과 등 물리 기반 애니메이션 구현도 쉽게 가능합니다.

블루프린트에 Skeletal Mesh 설정

  • 컴포넌트 트리에서 Mesh (CharacterMesh0) 컴포넌트를 선택
  • 우측 Details 패널의 Skeletal Mesh 항목에 스켈레탈 메시를 할당
  • 메시를 적용하면 뷰포트에 자동으로 캐릭터 외형이 표시되고, 머티리얼도 기본으로 연결됨

 

메시 방향 조정

  • 언리얼에서 일반적으로 캐릭터의 전방 방향은 X축
  • 그러나 SKM_Manny나 SKM_Quinn의 모델은 Y축을 전방으로 사용하기 때문에, 적용 후 캐릭터가 옆을 보는 것처럼 보일 수 있습니다.
  • 이를 해결하려면 Mesh 컴포넌트 선택 후 Details 패널에서 RotationYaw(Z축) 값을 -90도로 조정.
    • 이렇게 하면 캐릭터가 엔진의 전방(X축)을 바라보게 됩니다.

 

캡슐 컴포넌트 위치에 맞게 메시 위치 조절

 

움직이는 게 좀 더 세밀했으면 좋겠다면 체크된 곳의 숫자를 줄이면 됨. 

 

 

캡슐 컴포넌트 크기 변경

 

  • 언리얼의 Character 클래스는 최상위 루트로 CapsuleComponent(캡슐 형태 충돌체)를 사용합니다.
  • 그 내부 중앙 부분에 Skeletal Mesh가 위치하게 됩니다.
  • 블루프린트 뷰포트에서 Mesh 컴포넌트를 선택한 뒤, Location 값을 조정해 캐릭터의 발이 캡슐 바닥에 정확히 닿도록 위치 조정
  • 캡슐 충돌 범위가 너무 작거나 크면 게임 플레이 시 충돌 문제가 발생할 수 있으므로, CapsuleComponent를 선택하고 Half Height, Radius 값을 적절히 조절하기!

<카메라 및 GameMode 설정하기>

3인칭 게임에서는 플레이어가 캐릭터의 뒤쪽이나 어깨 너머 시점을 보며 이동하는 경우가 많음

이를 위해 SpringArmCameraComponent를 추가하기

이후 GameMode 설정을 통해, 만든 캐릭터가 기본적으로 스폰되도록 구성하기

 

SpringArm 및 CameraComponent 추가

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "SpartaCharacter.generated.h"

//미리선언
class USpringArmComponent; // 스프링 암 관련 클래스 헤더
class UCameraComponent; // 카메라 관련 클래스 전방 선언

UCLASS()
class SPARTAPROJECT_API ASpartaCharacter : public ACharacter
{
		GENERATED_BODY()

public:
		ASpartaCharacter();

protected:
	  // 스프링 암 컴포넌트
	  UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera")
	  USpringArmComponent* SpringArmComp;
	  // 카메라 컴포넌트
	  UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera")
	  UCameraComponent* CameraComp;
	
		virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override; // 이 함수는 이후에 다루게 되니, 우선 삭제하기 않고 둡니다.
};

 

uspringarmcomponent랑 ucameracomponent를 포함한 헤더파일을 위에 인클루드로 선언할 수 있지만 조금 낭비임. 

그래서 미리 선언을 함

그리고 나중에 진짜로 구현할 때 차라리 cpp 파일에다가 include를 하게 됨

헤더에서 선언할 때는 그냥 미리선언으로 이런 게 있다고 알려주기만 하면 됨.

 

  • VisibleAnywhere, BlueprintReadOnly: 블루프린트에서 보기만 가능하고, C++ 코드 쪽에서만 수정 가능하게 하는 속성입니다.
  • Forward Declaration (전방 선언)은 헤더 파일의 의존성을 줄이는 좋은 습관입니다. (필요할 때만 #include를 추가)
  • SpringArmComp
    • 스프링 암 컴포넌트(카메라 붐). 캐릭터와 카메라 간의 거리를 유지하고, 충돌 시 카메라가 벽 등에 박히지 않도록 위치를 자동 조정해줍니다.
  • CameraComp
    • 실제로 화면에 표시되는 카메라 컴포넌트입니다. 위치와 회전을 제어하면 게임 뷰가 변경됩니다.

 

#include "SpartaCharacter.h"
// 카메라, 스프링 암 실제 구현이 필요한 경우라서 include
#include "Camera/CameraComponent.h"
#include "GameFramework/SpringArmComponent.h"

ASpartaCharacter::ASpartaCharacter()
{
		// Tick 함수는 우선 꺼둡니다.
		PrimaryActorTick.bCanEverTick = false;
		
		// (1) 스프링 암 생성
    SpringArmComp = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
    // 스프링 암을 루트 컴포넌트 (CapsuleComponent)에 부착
    SpringArmComp->SetupAttachment(RootComponent);
    // 캐릭터와 카메라 사이의 거리 기본값 300으로 설정
    SpringArmComp->TargetArmLength = 300.0f;  
    // 컨트롤러 회전에 따라 스프링 암도 회전하도록 설정
    SpringArmComp->bUsePawnControlRotation = true;  

    // (2) 카메라 컴포넌트 생성
    CameraComp = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
    // 스프링 암의 소켓 위치에 카메라를 부착
    CameraComp->SetupAttachment(SpringArmComp, USpringArmComponent::SocketName);
    // 카메라는 스프링 암의 회전을 따르므로 PawnControlRotation은 꺼둠
    CameraComp->bUsePawnControlRotation = false;
}

void ASpartaCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
		Super::SetupPlayerInputComponent(PlayerInputComponent);
}

 

캡슐 컴포넌트가 루트 컴포넌트였음

거기에 스프링 암을 붙이는거임 (자손으로 붙음)

 

카메라는 루트에다 붙이지 않음. 삼각대에 붙여야 함. 삼각대 끝부분!

스프링암에 붙이고, 스프링암 지점들(소켓이라고 부름)중에서도 끝부분에 붙여야 함.

 

    CameraComp->SetupAttachment(SpringArmComp, USpringArmComponent::SocketName);

 

컨트롤러 회전에 따라 스프링암은 움직이는데 카메라는 움직이지 않게 설정을 해야 캐릭터를 자유롭게 볼 수 있되 카메라가 같이 움직이진 않아서 어지럽진 않게 됨.

 

visibleanywhere 쓰면 수정은 불가능하지만 속성들은 변경할 수 있음

 

  • SpringArmComp->bUsePawnControlRotation = true
    • 플레이어가 마우스를 움직이면 Controller의 회전 값이 변경되고, 이때 스프링 암도 같이 회전하도록 설정합니다.
    • 결과적으로 카메라도 따라 회전하여 3인칭 시점을 자연스럽게 구현할 수 있습니다.
  • CameraComp->bUsePawnControlRotation = false
    • 이미 스프링 암이 회전을 처리하므로, 카메라 자체는 PawnControlRotation을 사용하지 않도록 합니다.

 

 

 

카메라 위치 조정

 

 

 

게임모드 블루프린트 들어가서 default pawn class에서 캐릭터 지정

-> 이 게임 모드가 적용된 모든 레벨들은 이 캐릭터를 쓰겠다는 의미!

 

이걸 C++로 하는 법

GameMode에서 DefaultPawnClass 설정

 

<게임모드 헤더>

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/GameMode.h"
#include "SpartaGameMode.generated.h"

UCLASS()
class SPARTAPROJECT_API ASpartaGameMode : public AGameMode
{
    GENERATED_BODY()

public:
		ASpartaGameMode(); // 생성자 만들기
}

 

<게임모드 cpp>

#include "SpartaGameMode.h"
#include "SpartaCharacter.h"

ASpartaGameMode::ASpartaGameMode()
{
    DefaultPawnClass = ASpartaCharacter::StaticClass();
}
  • 이 코드가 있으면 게임 시작 시 SpartaCharacter가 자동으로 스폰되고, PlayerController와 연결되어 플레이어가 조작할 수 있게 됨

 

 

이걸 조정하면 게임이 시작되면 그 위치에 캐릭터가 스폰됨

 

  • 게임이 시작되면, DefaultPawnClass로 설정된 캐릭터는 맵에 배치된 Player Start 위치에 스폰됩니다. Player Start는 언리얼 엔진에서 기본 플레이어 캐릭터의 시작 위치를 지정하는 데 사용됩니다.
    • 맵에 Player Start가 배치되지 않은 경우, 언리얼 엔진은 캐릭터를 맵의 원점(0, 0, 0)에 스폰하려고 시도합니다. 하지만 충돌 문제로 인해 스폰이 실패할 수도 있습니다.
    • Place Actors 패널 > Basic 카테고리에서 Player Start를 선택해서 맵에 드래그 앤 드롭하면 추가하고, 위치를 원하는 스폰 지점으로 조정하세요.

 

C++로 전부 구현을 할지, 블루프린트로 한 번 감싸서 사용을 할지는 본인 취향 차이.

근데 블루프린트로 한 번 감싸서 하는 게 더 편한듯.

 

안전하게 하려면 둘 다 하는 것도 좋음!

 

 

+ Recent posts