Enhanced Input System이란?
말 그대로 향상된 입력 시스템을 뜻한다.
게임을 만들때 키보드를 이용해서 진행하도록 만드는 경우, 사용자가 게임 패드를 사용하는 경우 등 입력 장치들이 다양해짐에 따라 훨씬 쉽게 간단하게 입력을 받을 수 있도록 하기 위해 만들어진 시스템이다.
점프 기능을 만들고 그 기능에 스페이스바, 게임패트의 X버튼 등 연동만 하면 알아서 유저가 사용하는 입력 장치에 따라 동일하게 동작할 수 있게 해준다.
이를 이용하여 캐릭터의 움직임을 구현해보면 아래와 같다.
(참고로 언리얼의 C++ 프로젝트 기준으로 작성하였음)
우선 언리얼 내에서 Enhanced Input 플러그인을 활성화 시켜준다.
언리얼 프로젝트 폴더 내 bulid.cs 파일을 열어 ModuleNames.AddRange() 함수의 매개변수로 EnhancedInput 을 추가해주도록 한다.
bulid.cs 파일은 외부 모듈 사용 여부, PCH 사용 여부 등 설정하기 위한 파일이다.
여기서 우리가 사용할 모듈을 추가해줘야하는데 그게 바로 AddRange에 string 형태로 넣어주는 것이다.
그 다음 InputAction을 하나 새로 만들어준다.
IA(InputAction) : 역할에 대한 정보값을 구성하는 Asset 입력받는 정보를 정하는 것(Vector, bool, float 등).
ex) IA_Jump 는 bool형 true, false 값만 받을 것이다. 해당 된 키를 누르면 true, 누르지 않는다면 false
그 다음 IMC(Input Mapping Context)를 만들어준 뒤 IA에 어떤 키를 눌러야 정보 값을 넘겨줄지 설정한다.
**IMC란?
모든 IA를 관리하는 기능이다.
모든 Input Action들을 모아 특정 키와 맵핑시키는 역할을 한다.
IMC 설정 옵션
Negate : 반대의 값을 넣어준다.(음수)
Swizzle Input Axis Value : 넣어주는 값을 XYZ 순이 아닌 YXZ 처럼 순서를 바꿔준다.
즉, 바꾸지 않으면 X에 데이터를 넣어주는데 Y나 Z로 바꿔줌으로써 특정 축으로 들어오는 값을 분리할 수 있다.
Down : 키를 누르는 동안 계속해서 값이 들어온다.
Pressed : 키를 누르는 순간 값이 들어온다. (한번)
Released : 키를 떼는 순간 값이 들어온다. (한번)
원래 Input class로 받았다면 EnhancedInput에서는 InputAction로 값을 받아 Input Context로 넘기는 것이다.
(수치, true 등등)
실행중에도 동적으로 바꿀수 있도록 한 것이 바로 EnhancedInput이다.
이제 해당 키로 받아 온 값을 바탕으로 무엇을 할지 기능을 넣어야 하므로 Charater Class를 상속받아 새로운 Class를 만들어준다.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "InputActionValue.h"
#include "MyEnhancedInputCharacter.generated.h"
class UCameraComponent;
class USpringArmComponent;
class UInputAction;
UCLASS()
class L20240625_API AMyEnhancedInputCharacter : public ACharacter
{
GENERATED_BODY()
public:
AMyEnhancedInputCharacter();
protected:
virtual void BeginPlay() override;
public:
virtual void Tick(float DeltaTime) override;
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
TObjectPtr<UCameraComponent> Camera;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
TObjectPtr<USpringArmComponent> CameraBoom;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
TObjectPtr<UInputAction> IA_EnhancedMove;
UFUNCTION()
void Move(const FInputActionValue& Value);
};
header에서 우리가 사용할 함수, 변수를 선언해주도록 한다.
UFUNCTION(), UCLASS(), UPROPERTY()는 언리얼에서 제공해주는 매크로로 기존 C++의 기능을 더욱 확장해준다라고 볼 수이다. 이는 추후에 더 자세히 다루도록 하겠다.
또한, 포인터로 클래스를 사용하는 경우 굳이 해당 header를 Include하지 않고 전방선언을 하여 컴파일 시간을 단축해주도록 하자.
(순환 참조 문제도 방지된다.)
이제 header에서 선언한 함수를 cpp에서 구현해주도록 한다.
#include "MyEnhancedInputCharacter.h"
#include "Camera/CameraComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
AMyEnhancedInputCharacter::AMyEnhancedInputCharacter()
{
PrimaryActorTick.bCanEverTick = true;
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
CameraBoom->SetupAttachment(RootComponent);
Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
Camera->SetupAttachment(CameraBoom);
}
void AMyEnhancedInputCharacter::BeginPlay()
{
Super::BeginPlay();
}
void AMyEnhancedInputCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AMyEnhancedInputCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
UEnhancedInputComponent* MyEnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent);
if(MyEnhancedInputComponent)
{
MyEnhancedInputComponent->BindAction(IA_EnhancedMove, ETriggerEvent::Triggered, this, &AMyEnhancedInputCharacter::Move);
}
}
void AMyEnhancedInputCharacter::Move(const FInputActionValue& Value)
{
FVector2D MyVector = Value.Get<FVector2D>();
AddMovementInput(GetActorForwardVector() * MyVector.X);
AddMovementInput(GetActorRightVector() * MyVector.Y);
}
사용할때에는 UInputComponent의 자식인 UEnhancedInputComponent로 Cast하여 사용하자.
당연한 소리지만 자식 Class에서 별도로 추가한 함수들을 쓰기 위해선 형변환을 해줘야한다.
추가로 Controller도 구현해주도록 한다.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "MyEnhancedInputPlayerController.generated.h"
class UInputMappingContext;
UCLASS()
class L20240625_API AMyEnhancedInputPlayerController : public APlayerController
{
GENERATED_BODY()
public:
virtual void BeginPlay() override;
virtual void OnPossess(APawn* aPawn) override;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
TObjectPtr<UInputMappingContext> InputMappingContext;
};
#include "MyEnhancedInputPlayerController.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
void AMyEnhancedInputPlayerController::BeginPlay()
{
Super::BeginPlay();
}
void AMyEnhancedInputPlayerController::OnPossess(APawn* aPawn)
{
Super::OnPossess(aPawn);
if(InputMappingContext)
{
ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>
(GetLocalPlayer())->AddMappingContext(InputMappingContext, 0);
}
}
다 완성되고 나면 해당 C++을 상속받는 BP를 만들어주고, 우리가 만든 IA를 할당해주도록 한다.
이제 월드에 해당캐릭터를 배치하고 실행하면 우리가 맵핑한 키를 누르면 해당 동작하는 것을 볼 수 있다.
'Engine > Unreal' 카테고리의 다른 글
Unreal Dedicated Server 설정하기 (4) | 2025.07.10 |
---|---|
Unreal C++로 Black Jack Game 만들기(+열거형) (4) | 2025.07.09 |
언리얼의 기초 2 (0) | 2025.01.06 |
언리얼 엔진의 기초 (0) | 2024.11.27 |
언리얼 엔진에 fbx 파일 임포트 하기 (0) | 2024.11.22 |