언리얼

[ Unreal 5.4.2 ] Character 클래스 이동 구현 (EnhancedInput) 및 게임 모드 설정

Hexs 2024. 7. 16. 04:20
반응형

테스트 하는 동안 Default Pawn Class를 설정해주기 위해서 임시로Game Mode Base를 상속받은.

TestGameModeBase 스크립트를 생성해 주었습니다.

.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "TestGameModeBase.generated.h"

/**
 *
 */
UCLASS()
class TESTGAME_API ATestGameModeBase : public AGameModeBase
{
	GENERATED_BODY()

public:
	virtual void BeginPlay() override;
};

//
.cpp

#include "TestGameModeBase.h"

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

    if (GEngine)
    {
        GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("Hello, World!"));
    }
}

해당 코드가 정상적으로 작동하는지 확인하기 위해서.

BeginPlay를 사용해서 DebugMessage를 사용해서 Text를 출력합니다. - 게임 시작시.

 

 

해당 코드를 기반으로 Create Blueprint class based on TestGameModeBase를 눌러서

블루프린트를 생성해줍니다. 

 

이후 Project Settings -> Project 하위 Map & Modes 에서 Default Modes 에 있는 Default GameMode를 해당 블루프린트로 변경해줍니다.


EnhancedInput 을 사용하기 위해서 Input Action 과 Input Mapping Context를 생성해줍니다.

Content Browser 에서 우클릭.

 

Input Action 5개 ( Forward, Jump, LookX, LookY, Right ) 와 Input Mapping Context 1개를 만들어줍니다.

언리얼 엔진 5 공식 EnhancedInput 사용 방법에서는 Forward 와 Right 를 사용하지 않고 Move 하나로 사용하지만

오류가 생겨서 두개로 분할하여서 사용하였습니다.

 

IMC_Player를 클릭해서 키들을 Mapping 해줍니다.

 

Negate 를 사용하는 이유는 

Negate 를 사용하지 않는 경우 +를 반환하고

Negate 를 사용하면 - 를 반환하기 떄문에

앞뒤 양옆의 방향에 대한 값을 입력받기 위해서 입니다.

 

.h

#pragma once

#include "InputActionValue.h"
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Camera/CameraComponent.h"
#include "Projectile.h"

#include "CharacterController.generated.h"

UCLASS()
class TESTGAME_API ACharacterController : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	ACharacterController();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent *PlayerInputComponent) override;

private:
	// IMC
	UPROPERTY(editanywhere, category = input, meta = (allowprivateaccess = true))
	class UInputMappingContext *DefaultMappingContext;
	// IA_Jump
	UPROPERTY(editanywhere, category = input, meta = (allowprivateaccess = true))
	class UInputAction *JumpAction;

	UPROPERTY(editanywhere, category = input, meta = (allowprivateaccess = true))
	class UInputAction *ForwardAction;

	UPROPERTY(editanywhere, category = input, meta = (allowprivateaccess = true))
	class UInputAction *RightAction;

	UPROPERTY(editanywhere, category = input, meta = (allowprivateaccess = true))
	class UInputAction *LookXAction;
	UPROPERTY(editanywhere, category = input, meta = (allowprivateaccess = true))
	class UInputAction *LookYAction;

	UPROPERTY(VisibleAnywhere)
	UCameraComponent *CameraComponent;

protected:
	void Forward(const FInputActionValue &value);
	void Right(const FInputActionValue &value);

	//void Look(const FInputActionValue &value);
	void Jump() override;

	void LookX(const FInputActionValue &value);
	void LookY(const FInputActionValue &value);
  
  .cpp
  
#include "CharacterController.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"

#include "GameFramework/Character.h"

#include "Components/CapsuleComponent.h"
#include "GameFramework/CharacterMovementComponent.h"

#include "InputMappingContext.h"

// Sets default values
ACharacterController::ACharacterController()
{
	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	static ConstructorHelpers::FObjectFinder<UInputMappingContext> DEFAULT_CONTEXT(TEXT("/Script/EnhancedInput.InputMappingContext'/Game/Input/IMC_Player.IMC_Player'"));

	static ConstructorHelpers::FObjectFinder<UInputAction> IA_JUMP(TEXT("/ Script / EnhancedInput.InputAction'/Game/Input/IA_Jump.IA_Jump'"));

	static ConstructorHelpers::FObjectFinder<UInputAction> IA_Forward(TEXT("/ Script / EnhancedInput.InputAction'/Game/Input/IA_Forward.IA_Forward'"));
	static ConstructorHelpers::FObjectFinder<UInputAction> IA_Right(TEXT("/ Script / EnhancedInput.InputAction'/Game/Input/IA_Right.IA_Right'"));

	static ConstructorHelpers::FObjectFinder<UInputAction> IA_LOOKX(TEXT("/ Script / EnhancedInput.InputAction'/Game/Input/IA_LookX.IA_LookX'"));
	static ConstructorHelpers::FObjectFinder<UInputAction> IA_LOOKY(TEXT("/ Script / EnhancedInput.InputAction'/Game/Input/IA_LookY.IA_LookY'"));


	if (DEFAULT_CONTEXT.Succeeded())
	{
		DefaultMappingContext = DEFAULT_CONTEXT.Object;
	}

	if (IA_JUMP.Succeeded())
	{
		JumpAction = IA_JUMP.Object;
	}

	if (IA_Forward.Succeeded())
	{
		// GEngine->AddOnScreenDebugMessage(-1, 3.0f, FColor::Purple, TEXT("Found Forward Action"));
		ForwardAction = IA_Forward.Object;
	}

	if (IA_Right.Succeeded())
	{
		// GEngine->AddOnScreenDebugMessage(-1, 3.0f, FColor::Purple, TEXT("Found Right Action"));
		RightAction = IA_Right.Object;
	}

	if (IA_LOOKX.Succeeded())
	{
		LookXAction = IA_LOOKX.Object;
	}

	if (IA_LOOKY.Succeeded())
	{
		LookYAction = IA_LOOKY.Object;
	}

	CameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("PersonCamera"));
	CameraComponent->SetupAttachment(GetCapsuleComponent());
	CameraComponent->SetRelativeLocation(FVector(-110.0f, 0.0f, 245.0 + BaseEyeHeight));
	CameraComponent->SetRelativeRotation(FRotator(0.0, -30.0f, 0.0));
	CameraComponent->bUsePawnControlRotation = true;
}

// Called when the game starts or when spawned
void ACharacterController::BeginPlay()
{
	Super::BeginPlay();

	if (APlayerController *PlayerController = Cast<APlayerController>(GetController()))
	{
		// ULocalPlayer *LocalPlayer = PlayerController->GetLocalPlayer();
		if (UEnhancedInputLocalPlayerSubsystem *SubSystem =
				ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))

		{
			SubSystem->AddMappingContext(DefaultMappingContext, 0);
		}
	}
}

// Called every frame
void ACharacterController::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	FVector CurrentVelocity = GetCharacterMovement()->Velocity;

	// 이동 속도를 로그로 출력
	// UE_LOG(LogTemp, Warning, TEXT("Current Velocity: %s"), *CurrentVelocity.ToString());
	// GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Green, *CurrentVelocity.ToString());
}

// Called to bind functionality to input
void ACharacterController::SetupPlayerInputComponent(UInputComponent *PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	if (UEnhancedInputComponent *EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent))
	{
		EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Triggered, this, &ACharacterController::Jump);

		EnhancedInputComponent->BindAction(ForwardAction, ETriggerEvent::Triggered, this, &ACharacterController::Forward);
		EnhancedInputComponent->BindAction(RightAction, ETriggerEvent::Triggered, this, &ACharacterController::Right);

		EnhancedInputComponent->BindAction(LookXAction, ETriggerEvent::Triggered, this, &ACharacterController::LookX);
		EnhancedInputComponent->BindAction(LookYAction, ETriggerEvent::Triggered, this, &ACharacterController::LookY);
	}
}

void ACharacterController::Forward(const FInputActionValue &Value)
{
	FVector2D MovementVector = Value.Get<FVector2D>();
	// GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Green, MovementVector.ToString());
	//  플레이어의 현재 방향
	const FRotator Rotation = Controller->GetControlRotation();
	// Yaw만을 사용해 새로운 회전 생성
	const FRotator YawRotation(0.f, Rotation.Yaw, 0.f);
	// Yaw회전을 기준으로 전방 방향 계산
	const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);

	//  전방 방향과 Y값(전방 이동속도)을 사용하여 이동
	AddMovementInput(ForwardDirection, MovementVector.X);
}

void ACharacterController::Right(const FInputActionValue &Value)
{
	FVector2D MovementVector = Value.Get<FVector2D>();

	// GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, MovementVector.ToString());
	//  플레이어의 현재 방향
	const FRotator Rotation = Controller->GetControlRotation();
	// Yaw만을 사용해 새로운 회전 생성
	const FRotator YawRotation(0.f, Rotation.Yaw, 0.f);
	// Yaw회전을 기준으로 우측 방향 계산
	const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
	// 우측 방향과 X값(우측 이동속도)을 사용하여 이동

	AddMovementInput(RightDirection, MovementVector.X);
}
void ACharacterController::LookX(const FInputActionValue &Value)
{
	// 회전량
	const FVector2D LookVector = Value.Get<FVector2D>();
	//   X값(수평 회전량)을 사용해 yaw회전 추가 > 수평 시선 회전
	AddControllerYawInput(LookVector.X * 0.1f);
}
void ACharacterController::LookY(const FInputActionValue &Value)
{
	// 회전량
	const FVector2D LookVector = Value.Get<FVector2D>();
	//  Y값(수직 회전량)을 사용해 pitch회전 추가 > 수직 시선 회전
	AddControllerPitchInput(LookVector.X * 0.05f);
}

void ACharacterController::Jump()
{
	Super::Jump();
}

 

반응형