Unreal5 Enhanced Input 캐릭터 이동 및 점프 C++

Unreal5 Enhanced input 캐릭터 이동 및 점프 C++

안녕하세요.

오늘은 언리얼5에서 EnHanced input을 사용해서 캐릭터 이동과 점프를 구현해 보겠습니다.

그냥 공부한 내용 대충 작성하는거라 효율이랑은 거리가 멀겁니다.

  • 캐릭터 만들기.
  • Input Action & Mapping 생성
  • C++ SlayerCharacter.h 코드 작성.
  • Enhanced Input Module추가
  • C++ SlayerCharacter.cpp 코드 작성.
  • 마지막 설정.

캐릭터 만들기.

캐릭터 C++코드를 생성하고 이름을 SlayerCharacter로 설정했습니다.

이후 Blueprint파일을 하나 만들어 SlayerCharacter를 상속한 BP_SlayerCharacter를 만들었습니다.

BP_SlayerCharacter에서 Skeletal Mesh Asset을 적당한 것을 찾아 선택하였습니다.

InputAction & Mappping 생성

Enhanced input을 사용하기 위해 InputAction과 InputMappingContext를 생성했습니다.

Input Action은 IA_라는 이름을 사용했고, InputMappingContext는 IMC_라는 이름을 사용했습니다.

IA_Jump=bool, IA_Movement=Axis2D(Vector2D).

아래 사진은 공식 문서에 나온 내용입니다.

https://docs.unrealengine.com/5.1/ko/enhanced-input-in-unreal-engine/

위의 내용을 참고해 InputMappingContext를 구성하였습니다.

C++ SlayerCharacter.h 코드 작성.

SlayerCharacter.h의 protected부분에 코드를 추가하고 설정한 input을 눌렀을 때 작동할 함수를 선언하였습니다.

FInputActionValue는 UnrealEngine에서 제공하는 클래스 중 하나로, 사용자 입력 이벤트를 나타냅니다.

https://docs.unrealengine.com/4.26/en-US/API/Plugins/EnhancedInput/FInputActionValue/

 

FInputActionValue

 

docs.unrealengine.com

사용하기 위해서는 inputActionValue.h를 import해줘야 하고, EnhancedInput모듈이 필요합니다.

/*Enhanced input*/ 
//#include "InputActionValue.h" 를 추가해줘야함.
UPROPERTY(EditAnywhere, Category=Input)
UInputMappingContext* SlayerContext;
UPROPERTY(EditAnywhere, Category = Input)
UInputAction* MovementAction;
UPROPERTY(EditAnywhere, Category = Input)
UInputAction* JumpAction;
void Move(const FInputActionValue& value);
void Jump() override;

이후 UCLASS()윗부분에 class UInputMappingContext, class UInputAction을 추가하였습니다.

class UInputMappingContext;
class UInputAction;

.h파일의 전체 코드는 다음과 같습니다.

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "InputActionValue.h"
#include "SlayerCharacter.generated.h"
class UInputMappingContext;
class UInputAction;
UCLASS()
class SLAYER_API ASlayerCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	ASlayerCharacter();
	// Called every frame
	virtual void Tick(float DeltaTime) override;
	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	/*Enhanced input*/ 
	//#include "InputActionValue.h"
	UPROPERTY(EditAnywhere, Category=Input)
	UInputMappingContext* SlayerContext;
	UPROPERTY(EditAnywhere, Category = Input)
	UInputAction* MovementAction;
	UPROPERTY(EditAnywhere, Category = Input)
	UInputAction* JumpAction;
	void Move(const FInputActionValue& value);
	void Jump() override;
};

 

 

 

 

 

Enhanced Input Module 추가.

헤더파일의 코드는 작성했는데 아직 빨간 줄이 보이네요.

모듈추가를 아직 안 해서 그런 것 같습니다.

언리얼 5.1이면 자동으로 추가되는 줄 알았는데 제 컴퓨터는 해당되지 않나봅니다...ㅎㅎ

Slayer.Build.cs로 이동해서 PublicDependencyModuleNames.AddRange에 "EnhancedInput"을 추가하겠습니다.

이제 프로젝트 경로로 이동해 줍니다.

저는 E:\UReal\Slayer위치에 있습니다.

해당 위치에서 Binaries, Intermediate, saved폴더를 삭제합니다.

이후 Slayer.uproject를 우클릭해서 "Generate Visual Studio project files"를 눌러줍니다.

C++ SlayerCharacter cpp 코드 작성.

먼저 헤더파일에서 작성한 함수 정의를 해줍니다.

이제 이걸 C++로 구현해 주면 됩니다.

Begin play()에 이렇게 작성했습니다. 

//#include "EnhancedInputSubsystems.h" 추가 필요.
if (APlayerController* PlayerController = Cast<APlayerController>(GetController())) {
	if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer())) {
		Subsystem->AddMappingContext(SlayerContext, 0);
	}
}

https://docs.unrealengine.com/4.26/en-US/API/Plugins/EnhancedInput/UEnhancedInputLocalPlayerSubsyst-/

 

UEnhancedInputLocalPlayerSubsystem

Per local player input subsystem.

docs.unrealengine.com

점프는 그냥 구현된 것을 사용하겠습니다.

void ASlayerCharacter::Jump()
{
	Super::Jump(); //Character.h에 있는 Jump사용.
}

https://docs.unrealengine.com/4.27/en-US/API/Runtime/Engine/GameFramework/ACharacter/Jump/

 

ACharacter::Jump

Make the character jump on the next update.

docs.unrealengine.com

Move함수(움직임) 구현.

const FVector2D MovementVector = value.Get<FVector2D>();
const FRotator Rotation = Controller->GetControlRotation();
const FRotator YawRotation(0.f, Rotation.Yaw, 0.f);
const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
AddMovementInput(ForwardDirection, MovementVector.Y);
const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
AddMovementInput(RightDirection, MovementVector.X);

기능은 다 만들었으니까 이제 bind 해주겠습니다.

SetupPlayerInputComponent에서 아래 코드들을 입력해서 bind 해줍니다.

//#include "EnhancedInputComponent.h"추가.
if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent)) {
	EnhancedInputComponent->BindAction(MovementAction, ETriggerEvent::Triggered, this, &ASlayerCharacter::Move);
	EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Triggered, this, &ASlayerCharacter::Jump);
}

https://docs.unrealengine.com/4.26/en-US/API/Plugins/EnhancedInput/UEnhancedInputComponent/

 

UEnhancedInputComponent

Implement an Actor component for input bindings.

docs.unrealengine.com

마지막 설정.

visual studio작업이 다 끝나면 빌드하고 실행해 줍니다.

Blueprint에서 캐릭터가 옆을 보고 있길래 Rotation좀 수정해 주고, IA_어쩌고랑, IMC_어쩌고로 저장했던 것을 추가해 주었습니다.

앞, 뒤, 양옆 모두 잘 움직이고 점프도 잘 되지만 고개가 돌아가지 않고 카메라도 캐릭터에 파묻혀있네요.

이건 카메라 추가해서 하고, 코드 좀 추가하면 되는 건데.. 생각보다 글이 길어져서 여기까지 하겠습니다.

전체 코드.

더보기

SlayerCharacter.h

// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "InputActionValue.h"
#include "SlayerCharacter.generated.h"

class UInputMappingContext;
class UInputAction;
UCLASS()
class SLAYER_API ASlayerCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	ASlayerCharacter();
	// Called every frame
	virtual void Tick(float DeltaTime) override;
	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	/*Enhanced input*/ 
	//#include "InputActionValue.h"
	UPROPERTY(EditAnywhere, Category=Input)
	UInputMappingContext* SlayerContext;
	UPROPERTY(EditAnywhere, Category = Input)
	UInputAction* MovementAction;
	UPROPERTY(EditAnywhere, Category = Input)
	UInputAction* JumpAction;
	void Move(const FInputActionValue& value);
	void Jump() override;
};

SlayerCharacter.cpp

// Fill out your copyright notice in the Description page of Project Settings.
#include "Character/SlayerCharacter.h"
#include "EnhancedInputSubsystems.h"
#include "EnhancedInputComponent.h"
// Sets default values
ASlayerCharacter::ASlayerCharacter()
{
 	// 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;
}

// Called when the game starts or when spawned
void ASlayerCharacter::BeginPlay()
{
	Super::BeginPlay();
	//#include "EnhancedInputSubsystems.h" 추가 필요.
	if (APlayerController* PlayerController = Cast<APlayerController>(GetController())) {
		if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer())) {
			Subsystem->AddMappingContext(SlayerContext, 0);
		}
	}
}

void ASlayerCharacter::Move(const FInputActionValue& value)
{
	const FVector2D MovementVector = value.Get<FVector2D>();
	const FRotator Rotation = Controller->GetControlRotation();
	const FRotator YawRotation(0.f, Rotation.Yaw, 0.f);
	const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
	AddMovementInput(ForwardDirection, MovementVector.Y);//이동
	const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
	AddMovementInput(RightDirection, MovementVector.X);//이동
}

void ASlayerCharacter::Jump()
{
	Super::Jump(); //Character.h에 있는 Jump사용.
}

// Called every frame
void ASlayerCharacter::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
}

// Called to bind functionality to input
void ASlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	//#include "EnhancedInputComponent.h"추가.
	if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent)) {
		EnhancedInputComponent->BindAction(MovementAction, ETriggerEvent::Triggered, this, &ASlayerCharacter::Move);
		EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Triggered, this, &ASlayerCharacter::Jump);
	}
}

 

Designed by JB FACTORY