[UE5] 언리얼 엔진의 Enhanced Input 알아보기

연하·2024년 4월 22일
0

Unreal Engine Study

목록 보기
3/9
post-thumbnail

[참고] https://velog.io/@yoo06/UE5-Enhanced-Input-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0

향상된 입력을 정리하려고 공부하다가 너무너무 잘 정리되어 있는 벨로그 글을 발견했다. 개념적인 부분은 이 글을 많이 차용했고 공식 문서에서 필요한 내용만 조금씩 덧붙여 작성했기 때문에 출처를 남긴다 :) 구현부분은 생략하고 내가 배운대로 작성했으므로, 더 자세히 알고싶다면 위 링크의 글을 읽어보는 것을 추천한다!

Enhanced Input

향상된 입력을 사용하면 런타임 시 플레이어에 대한 매핑 컨텍스트(Mapping Contexts)를 추가하고 제거할 수 있다. 이를 통해 수많은 액션(Action)을 더 쉽게 관리할 수 있다.

Enhanced Input은 크게 4가지 특징을 가지고 있다.

  • Input Actions(입력 액션)
  • Input Mapping Contexts(입력 매핑 컨텍스트)
  • Input Modifiers(입력 모디파이어)
  • Input Triggers(입력 트리거)

Input Action

Input Action은, 액션이 할당되는 부분이다. 액션(Action) 및 축(Axis) 매핑 이름과 개념적으로 같다. 각 입력은 '웅크리기'나 '무기 발사'같은 사용자가 할 수 있는 행동을 나타내야 한다.

입력 액션은 여러 타입이 될 수 있으며, 타입에 따라 액션의 동작이 결정된다. 부울 액션은 단순한 bool 값을 갖고, Axis1D는 float값을, Axis2D는 FVector2D, 그리고 Axis3D는 전부 FVector이다.

가령 '문을 연다', '장비를 착용한다'와 같은 동작은 bool 값으로 지정하면 되고, 이동같은 동작은 Vector2D로 설정해주면 된다.

Value Type을 통해 지정 가능하다.

Content Drawer에서 우클릭 - Input - Input Action을 클릭해 생성할 수 있다.

Input Mapping Context

Input Mapping Context는 플레이어가 처할 수 있는 특정 컨텍스트를 나타내는 입력 액션 컬렉션으로, 주어진 입력 액션의 트리거 규칙을 설명한다. Input Action바인딩하는 곳이라고 보면 된다.

사용자는 여러개의 Input Mapping Context를 가질 수 있으며, 이들은 각각 우선순위가 있어 같은 키를 입력해도 어떤 액션이 나갈지를 지정할 수 있게 된다.

플레이어는 걷기와 인벤토리를 탐색할 때 각각의 Input Mapping Context를 가질 수 있다. 이때 같은 WASD를 누르더라도, 인벤토리를 열었다면 인벤토리를 탐색하도록 우선순위를 정할 수 있다.

Input Modifiers

Modifiers는 입력 받은 값을 변환해주는 장치이다.

W를 보면 Modifiers에서 Swizzle Input Axis Values가 설정되어 있고, 순서가 YXZ로 되어있다. 원래 입력을 받으면 XYZ의 순서로 받게 되는데(이 경우 Modifier가 없다면 W를 누르면 X가 1이 된다) 이를 YXZ의 순서로 받게 하여 W를 입력 시 Y가 1이 되도록 설정하는 것이다.

S를 보면 추가로 Negate라는 항목이 추가되어있다. Negate는 입력받은 값을 반대로 만들어주는 역할이고, X, Y, Z 각각 설정해줄 수 있다. (이 경우에는 Y에만 추가해도 되지만, 가시성을 위해 3가지 축 모두 설정되어 있다)

이처럼 Modifiers를 적절하게 사용하면 하나의 입력액션으로 다양한 역할을 할 수 있다.

Input Triggers

TriggersModifiers를 통해 입력 받은 값을 어떻게 활용할 지 정하게 된다. 짧게 누르면 약공격, 길게 누르면 차지어택이 나간다면, 이를 모두 트리거에서 제어가 가능하다.

Enhanced Input 설정하기

5.3 버전 기준으로 플러그인이 활성화 되어있어서 그부분은 생략하고 작성! 모듈은 프로젝트이름.Build.cs의 모듈 목록에 "EnhancedInput" 를 추가해주면 된다.

먼저 사용할 InputAction, Input Mapping Context를 만들어주고 설정까지 마쳐주자. InputAction은 Value Type만 설정해줘도 충분한 것 같고, Input Mapping Context에선 해당 액션의 Key, Modifiers를 설정해주어야 한다.

// PlayerController.h

UCLASS()
class MENTORING_0419_API ASamplePlayerController : public APlayerController
{
	GENERATED_BODY()

public:
	virtual void BeginPlay() override;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
	class UInputMappingContext* DefaultIMC;
};
// PlayerController.cpp

#include "SamplePlayerController.h"
#include "EnhancedInputSubSystems.h" // 헤더 추가

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

	UEnhancedInputLocalPlayerSubsystem* SubSystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer());
	if (SubSystem && DefaultIMC)
	{
		SubSystem->AddMappingContext(DefaultIMC, 0);
	}
}

InputMappingContext 포인터를 멤버변수로 추가하고 플러그인을 초기화 해준다.

C++ Playercontroller를 상속받은 블루프린트를 만들고, InputMappingContext를 넣어준다.

// PlayerCharacter.h
// 관련되지 않은 전처리기, 함수 모두 생략

#include "InputActionValue.h" // 헤더 추가

UCLASS()
class MENTORING_0419_API ASampleCharacter : public ACharacter
{
public:	
	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
	class UInputAction* LookAction;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
	class UInputAction* MoveAction;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
	class UInputAction* JumpAction;

	void Look(const FInputActionValue& Value);

	void Move(const FInputActionValue& Value);
};

사용하고자 하는 InputAction을 캐릭터의 멤버 변수로 추가해주고, InputAction이 들어올 때 호출하기 위한 함수를 만들어주자.

// PlayerCharacter.cpp

#include "EnhancedInputComponent.h" // 헤더 포함

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

	UEnhancedInputComponent* UIC = Cast<UEnhancedInputComponent>(PlayerInputComponent);
	if (UIC)
	{
		UIC->BindAction(LookAction, ETriggerEvent::Triggered, this, &ASampleCharacter::Look);
		UIC->BindAction(MoveAction, ETriggerEvent::Triggered, this, &ASampleCharacter::Move);
		UIC->BindAction(JumpAction, ETriggerEvent::Triggered, this, &ASampleCharacter::Jump);
	}
}

void ASampleCharacter::Look(const FInputActionValue& Value)
{
	// 구현 생략
}

void ASampleCharacter::Move(const FInputActionValue& Value)
{
	// 구현 생략
}

PlayerInputComponent를 다운캐스팅 해주고, InputAction을 바인딩해준다.

마찬가지로 블루프린트에서 해당하는 Input Action을 넣어주면 된다!

0개의 댓글