언리얼 엔진 5 / 캐릭터 조작 ( 이동 / 점프 / 회전 )

캐릭터 조작 직접 만들기

기본적으로 제공 되는 thirdpersoncharacter가 어떻게 움직이는지 궁금해서 작성해보았습니다.

아래에 있는 언리얼 문서와 블로그를 참고 하였습니다.

 

언리얼 문서 링크

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/enhanced-input-in-unreal-engine?application_version=5.4

 

참고한 블로그

https://intunknown.tistory.com/entry/Unreal5-Enhanced-Input-%EC%BA%90%EB%A6%AD%ED%84%B0-%EC%9D%B4%EB%8F%99-%EB%B0%8F-%EC%A0%90%ED%94%84-C

 

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

Unreal5 Enhanced input 캐릭터 이동 및 점프 C++ 안녕하세요. 오늘은 언리얼5에서 EnHanced input을 사용해서 캐릭터 이동과 점프를 구현해 보겠습니다. 그냥 공부한 내용 대충 작성하는거라 효율이랑은 거

intunknown.tistory.com

 

IA_Movement, IA_LookAround

캐릭터 이동 관련InputAction인 IA_Movement와 캐릭터 시선 ( 카메라 회전 ) 관련 IA_LookAround를 만듭니다.

 

입력 액션 은 향상된 입력 시스템과 프로젝트 코드 간의 통신 링크입니다. 입력 액션은 데이터 에셋이라는 점만 다를 뿐, 액션 및 축(Axis) 매핑 이름과 개념적으로 같습니다. 각 입력 액션은 '웅크리기'나 '무기 발사' 같은 사용자가 할 수 있는 행동을 나타내야 합니다. 입력 액션의 스테이트가 변경될 때 블루프린트 또는 C++에 입력 리스너(Input Listeners) 를 추가할 수 있습니다.

입력 액션은 여러 타입이 될 수 있으며, 타입에 따라 액션의 동작이 결정됩니다. 단순한 부울 액션을 만들 수도 있고 더욱 복잡한 3D 축을 만들 수도 있습니다. 액션 타입이 그 값을 결정합니다. 부울 액션은 단순한 bool 값을 갖고, Axis1D 는 float 값을, Axis2D 는 FVector2D , 그리고 Axis3D 는 전부 FVector 입니다.

 

둘다 액션의 모디파이어를 Axis2D (Vector2D)로 합니다.

IMC_Player

캐릭터 입력 매핑 컨텍스트인 IMC_Player를 만듭니다.

 

입력 매핑 컨텍스트 는 플레이어가 처할 수 있는 특정 컨텍스트를 나타내는 입력 액션 컬렉션으로, 주어진 입력 액션의 트리거 규칙을 설명합니다. 각 사용자에게 매핑 컨텍스트를 동적으로 추가하거나 제거하거나 우선순위를 지정할 수 있습니다.

입력 매핑 컨텍스트를 생성하려면 컨텍스트 브라우저 를 우클릭한 다음, 입력(Input) 옵션을 펼치고 입력 매핑 컨텍스트(Input Mapping Context) 를 선택합니다.

 

각각 키별로 모디파이 세팅 방법입니다.

언리얼 문서 발췌

 

wasd말고도 점프와 카메라 키 매핑 방법

 

PlayerCharacter

사용할 캐릭터 cpp 클래스를 만듭니다.

아래는 전체 파일 첨부입니다.

PlayerCharacter.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 "PlayerCharacter.generated.h"
class UInputMappingContext;
class UInputAction;
class USpringArmComponent;
class UCameraComponent;

UCLASS()
class WINTER_API APlayerCharacter : public ACharacter
{
	GENERATED_BODY()

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

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

	// 입력 맵핑 컨텍스트
	UPROPERTY(EditAnywhere, Category=Input)
	UInputMappingContext * PlayerContext;

	// 이동
	UPROPERTY(EditAnywhere, Category = Input)
	UInputAction* MovementAction;	

	// 점프
	UPROPERTY(EditAnywhere, Category = Input)
	UInputAction* JumpAction;

	// 카메라
	UPROPERTY(EditAnyWhere, Category = Input)
	UInputAction* LookAction;

	void Look(const FInputActionValue& value);
	void Move(const FInputActionValue& value);
	void Jump() override;
private:
	// 카메라 붐
	USpringArmComponent* CameraBoom;
	// 카메라
	UCameraComponent* ViewCamera;
public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

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

};

PlayerCharacter.cpp

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


#include "PlayerCharacter.h"
#include "EnhancedInputSubsystems.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "EnhancedInputComponent.h"
// Sets default values
APlayerCharacter::APlayerCharacter()
{


 	// 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;

	// 충돌 캡슐 크기 설정
	GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);

	// 캐릭터 회전
	bUseControllerRotationPitch = false;
	bUseControllerRotationYaw = false;
	bUseControllerRotationRoll = false;

	// 캐릭터 이동 관련
	GetCharacterMovement()->bOrientRotationToMovement = true;
	GetCharacterMovement()->RotationRate = FRotator(0.0f, 500.0f, 0.0f);

	// 빠른 반복 작업을 위해 이러한 변수들은 캐릭터 블루프린트에서 조정 가능
	GetCharacterMovement()->JumpZVelocity = 700.f;
	GetCharacterMovement()->AirControl = 0.35f;
	GetCharacterMovement()->MaxWalkSpeed = 500.f;
	GetCharacterMovement()->MinAnalogWalkSpeed = 20.f;
	GetCharacterMovement()->BrakingDecelerationWalking = 2000.f;
	GetCharacterMovement()->BrakingDecelerationFalling = 1500.0f;
	
	// 카메라 붐
	CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
	CameraBoom->SetupAttachment(RootComponent);
	CameraBoom->TargetArmLength = 400.0f;
	CameraBoom->bUsePawnControlRotation = true;



	

	// 카메라
	ViewCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("ViewCamera"));
	ViewCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName);
	ViewCamera->bUsePawnControlRotation = false;

}

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


}

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

}

// Called to bind functionality to input
void APlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	// UEnhancedInputLocalPlayerSubsystem 설정 
	if (APlayerController* PlayerController = Cast<APlayerController>(GetController()))
	{
		if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
		{
			Subsystem->AddMappingContext(PlayerContext, 0);
		}
	}
	// 바인딩 설정
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent))
	{
		EnhancedInputComponent->BindAction(MovementAction, ETriggerEvent::Triggered, this, &APlayerCharacter::Move);
		EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Triggered, this, &APlayerCharacter::Jump);
		EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &APlayerCharacter::Look);
	}
}
void APlayerCharacter::Move(const FInputActionValue& value)
{
	// 플레이어 이동
	const FVector2D MovementVector = value.Get<FVector2D>();

	if (Controller != nullptr)
	{
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator YawRotation(0, Rotation.Yaw, 0);

		// 앞 벡터
		const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
		// 오른쪽 벡터
		const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);

		AddMovementInput(ForwardDirection, MovementVector.Y);
		AddMovementInput(RightDirection, MovementVector.X);
	}
	else
	{
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Controller is null"));
	}
}
void APlayerCharacter::Jump()
{
	Super::Jump();
}

// 카메라
void APlayerCharacter::Look(const FInputActionValue& value)
{
	const FVector2D LookVector = value.Get<FVector2D>();
	if (Controller != nullptr)
	{
		// 좌우
		AddControllerYawInput(LookVector.X);
		// 상하
		AddControllerPitchInput(LookVector.Y);
	}
	else
	{
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Controller is null"));
	}

}

BP_PlayerCharacter

코드를 작성하였으면 자식클랙스로 BP_PlayerCharacter를  만듭니다.

BP_PlayerCharacter 안에서 입력에 있는

컨텍스트와 입력액션들을 맵핑해줍니다.

메시와 애니메이션 블루프린트를 넣어줍니다.

게임모드의 디폴트 폰 클래스를 변경해주고 테스트 해봅니다.

실행 영상