[UE5 C++] 플레이어 캐릭터 생성 - 2

LeeTaes·2024년 4월 24일
0

[UE_Project] MysticMaze

목록 보기
3/17
post-thumbnail

언리얼 엔진을 사용한 RPG 프로젝트 만들기

  • 간단한 플레이어 캐릭터를 C++로 생성하기
    - 플레이어 컨트롤러를 추가하고, 기본으로 설정하기
    - 기본적인 입력 추가하기 (상하좌우 이동 및 화면 전환)

플레이어 컨트롤러 생성하고 기본으로 지정하기

  • 추후 HUD 및 기타 작업을 하기 위한 PlayerController 클래스를 생성해보도록 하겠습니다.

MMPlayerController Class

  • 지금은 생성만 하고 GameMode에 등록해주도록 합니다.
// MMPlayerController Header
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "MMPlayerController.generated.h"

/**
 * 
 */
UCLASS()
class MYSTICMAZE_API AMMPlayerController : public APlayerController
{
	GENERATED_BODY()
	
};
  • 게임모드에서 PlayerControllerClass로 지정해주도록 합니다.
    - ConstructorHelpers::FClassFinder를 통해 클래스 정보를 찾아 등록합니다.
// MMGameMode CPP

AMMGameMode::AMMGameMode()
{
	...
    
	// PlayerControllerClass 설정
	static ConstructorHelpers::FClassFinder<APlayerController> ControllerClassRef(TEXT("/Script/CoreUObject.Class'/Script/MysticMaze.MMPlayerController'"));
	if (ControllerClassRef.Succeeded())
	{
		PlayerControllerClass = ControllerClassRef.Class;
	}
}
  • 결과는 다음과 같습니다.

플레이어 입력 추가하기

  • 언리얼 5.1버전부터 향상된 입력(Enhanced Input)이 기본으로 설정되어 있습니다.
  • 향상된 입력을 사용해 플레이어의 이동을 구현해보도록 하겠습니다.
    [향상된 입력 문서]
  • 프로젝트에서 사용할 입력 버전은 크게 3가지로 나뉩니다.

    1. 기본 상태의 입력
    2. 활 조준 상태의 입력
    3. 스킬 캐스팅 중의 입력
  • 우선 기본 상태의 이동을 구현해보도록 하겠습니다.

  1. 입력 액션을 추가합니다. (BasicMove, BasicLook)

  2. 입력 매핑 컨텍스트를 추가합니다. (IMC_BasicPlayer)

  1. IMC_BasicPlayer에서 액션들을 매핑시켜주도록 합니다.


C++ 코드를 통해 플레이어에게 입력 시스템 적용하기

MMPlayerCharacter Class

  • 위에서 생성한 IA와 IMC를 찾아 등록하고, 함수를 매핑하여 실제로 동작하도록 구현해보도록 하겠습니다.
// MMPlayerCharacter Header
#include "InputActionValue.h"

...

UCLASS()
class MYSTICMAZE_API AMMPlayerCharacter : public AMMCharacterBase
{
	GENERATED_BODY()
	
    ...
    
// Input Section
protected:
	// 입력에 따라 매핑될 함수를 선언합니다.
	void BasicMove(const FInputActionValue& Value);
	void BasicLook(const FInputActionValue& Value);

	UPROPERTY(VisibleAnywhere, Category = Input, Meta = (AllowPrivateAccess = "true"))
	TObjectPtr<class UInputMappingContext> IMC_Basic;

	UPROPERTY(VisibleAnywhere, Category = Input, Meta = (AllowPrivateAccess = "true"))
	TObjectPtr<class UInputAction> IA_BasicMove;

	UPROPERTY(VisibleAnywhere, Category = Input, Meta = (AllowPrivateAccess = "true"))
	TObjectPtr<class UInputAction> IA_BasicLook;
};
// MMPlayerCharacter CPP

#include "Character/MMPlayerCharacter.h"

#include "Components/CapsuleComponent.h"
#include "Camera/CameraComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "InputAction.h"
#include "InputMappingContext.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"

AMMPlayerCharacter::AMMPlayerCharacter()
{
	...

	// Input
	{
		static ConstructorHelpers::FObjectFinder<UInputMappingContext>IMC_BasicRef(TEXT("/Script/EnhancedInput.InputMappingContext'/Game/MysticMaze/Player/Control/IMC_BasicPlayer.IMC_BasicPlayer'"));
		if (IMC_BasicRef.Object)
		{
			IMC_Basic = IMC_BasicRef.Object;
		}

		static ConstructorHelpers::FObjectFinder<UInputAction>IA_BasicMoveRef(TEXT("/Script/EnhancedInput.InputAction'/Game/MysticMaze/Player/Control/InputAction/IA_BaseMove.IA_BaseMove'"));
		if (IA_BasicMoveRef.Object)
		{
			IA_BasicMove = IA_BasicMoveRef.Object;
		}

		static ConstructorHelpers::FObjectFinder<UInputAction>IA_BasicLookRef(TEXT("/Script/EnhancedInput.InputAction'/Game/MysticMaze/Player/Control/InputAction/IA_BaseLook.IA_BaseLook'"));
		if (IA_BasicLookRef.Object)
		{
			IA_BasicLook = IA_BasicLookRef.Object;
		}
	}

	// Setting (기본적으로 원하는 기본 이동을 위한 캐릭터 설정)
	{
		// 컨트롤러의 Rotation에 영향 X
		bUseControllerRotationPitch = false;
		bUseControllerRotationYaw = false;
		bUseControllerRotationRoll = false;

		// 폰의 컨트롤 회전 사용
		SpringArm->bUsePawnControlRotation = true;

		// 움직임에 따른 회전 On
		GetCharacterMovement()->bOrientRotationToMovement = true;
	}
}

void AMMPlayerCharacter::BeginPlay()
{
	Super::BeginPlay();

	APlayerController* PlayerController = Cast<APlayerController>(GetController());
	if (PlayerController && IMC_Basic)
	{
    	// 서브시스템 불러오기
		if (UEnhancedInputLocalPlayerSubsystem* SubSystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
		{
			// 매핑 컨텍스트 추가
			SubSystem->AddMappingContext(IMC_Basic, 0);
			// 입력 시작
			EnableInput(PlayerController);
		}
	}
}

void AMMPlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	// 향상된 입력 컴포넌트로 형변환
    // * CastChecked : 캐스팅이 실패할 경우 프로그램을 중단시키는 대신 에러 메시지 출력
	UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent);

	// 생성된 IA_BasicLook, IA_BasicMove와 함수 매핑
	EnhancedInputComponent->BindAction(IA_BasicLook, ETriggerEvent::Triggered, this, &AMMPlayerCharacter::BasicLook);
	EnhancedInputComponent->BindAction(IA_BasicMove, ETriggerEvent::Triggered, this, &AMMPlayerCharacter::BasicMove);
}

void AMMPlayerCharacter::BasicMove(const FInputActionValue& Value)
{
	// 입력받은 Value로부터 MovementVector 가져오기
	FVector2D MovementVector = Value.Get<FVector2D>();

	// 컨트롤러의 회전 중 Yaw(Z)를 가져와 저장
	const FRotator Rotation = Controller->GetControlRotation();
	const FRotator YawRotation(0, Rotation.Yaw, 0);

	// 회전(Yaw)을 기반으로 전방 및 오른쪽 방향을 받아오기 (X : 전방, Y : 오른쪽)
	const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
	const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);

	// Movement에 값 전달 (방향, 이동량)
	AddMovementInput(ForwardDirection, MovementVector.X);
	AddMovementInput(RightDirection, MovementVector.Y);
}

void AMMPlayerCharacter::BasicLook(const FInputActionValue& Value)
{
	// 입력받은 Value로부터 LookVector 가져오기
	FVector2D LookVector = Value.Get<FVector2D>();
	
	// Controller에 값 전달
	AddControllerYawInput(LookVector.X);
	AddControllerPitchInput(LookVector.Y);
}

에러 : WS는 좌우로, AD는 앞뒤로 이동되는 결과 초래

  • IA_BasicMove에서 Modifier를 추가해주도록 합니다.

결과 확인

  • 애니메이션은 없지만 입력을 통해 이동 및 화면 전환이 가능해졌습니다.
profile
클라이언트 프로그래머 지망생

0개의 댓글