UE5 Enhanced Input System 가이드
개요 — Legacy Input vs Enhanced Input
Section titled “개요 — Legacy Input vs Enhanced Input”UE5에서 기존 BindAxis / BindAction 기반의 Legacy Input System은 Enhanced Input System으로 대체되었습니다. Enhanced Input은 런타임 컨텍스트 전환, 복합 입력 매핑, 플랫폼별 리맵핑을 지원하는 데이터 기반 입력 시스템입니다.
| 기능 | Legacy Input | Enhanced Input |
|---|---|---|
| 런타임 리맵핑 | 불가 | 가능 |
| 컨텍스트 전환 (UI/전투) | 불가 | IMC로 즉시 전환 |
| 복합 입력 (Chord) | 제한적 | Trigger로 유연 지원 |
| 입력 수정자 (Dead Zone, Swizzle) | 제한적 | Modifier로 풍부한 변환 |
| 플랫폼별 기본 키 | 수동 | 자동 구성 가능 |
1. 프로젝트 설정
Section titled “1. 프로젝트 설정”1.1 플러그인 및 모듈 추가
Section titled “1.1 플러그인 및 모듈 추가”YourGame.Build.cs에 모듈을 추가합니다.
PublicDependencyModuleNames.AddRange(new string[]{ "Core", "CoreUObject", "Engine", "InputCore", "EnhancedInput" // 추가});1.2 기본 입력 클래스 설정
Section titled “1.2 기본 입력 클래스 설정”프로젝트 세팅에서 Default Player Input Class와 Default Input Component Class를 변경합니다.
Config/DefaultInput.ini:
[/Script/Engine.InputSettings]DefaultPlayerInputClass=/Script/EnhancedInput.EnhancedPlayerInputDefaultInputComponentClass=/Script/EnhancedInput.EnhancedInputComponent2. 에셋 생성 (에디터)
Section titled “2. 에셋 생성 (에디터)”Enhanced Input은 두 가지 데이터 에셋을 사용합니다.
- InputAction (IA): 단일 논리적 행동 정의 (예:
IA_Jump,IA_Move) - Input Mapping Context (IMC): 물리 키와 IA를 연결하는 컨텍스트 그룹
에디터에서 생성: 우클릭 > Input > Input Action / Input Mapping Context
3. C++ 구현
Section titled “3. C++ 구현”3.1 캐릭터 헤더
Section titled “3.1 캐릭터 헤더”#pragma once
#include "CoreMinimal.h"#include "GameFramework/Character.h"#include "InputActionValue.h"#include "MyCharacter.generated.h"
class UInputMappingContext;class UInputAction;
UCLASS()class MYGAME_API AMyCharacter : public ACharacter{ GENERATED_BODY()
public: AMyCharacter();
protected: virtual void BeginPlay() override; virtual void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) override;
private: // IMC (에디터에서 할당) UPROPERTY(EditDefaultsOnly, Category = "Input") TObjectPtr<UInputMappingContext> DefaultMappingContext;
// InputActions (에디터에서 할당) UPROPERTY(EditDefaultsOnly, Category = "Input") TObjectPtr<UInputAction> IA_Move;
UPROPERTY(EditDefaultsOnly, Category = "Input") TObjectPtr<UInputAction> IA_Look;
UPROPERTY(EditDefaultsOnly, Category = "Input") TObjectPtr<UInputAction> IA_Jump;
UPROPERTY(EditDefaultsOnly, Category = "Input") TObjectPtr<UInputAction> IA_Sprint;
// 입력 핸들러 void HandleMove(const FInputActionValue& Value); void HandleLook(const FInputActionValue& Value); void HandleJump(const FInputActionValue& Value); void HandleSprintStarted(const FInputActionValue& Value); void HandleSprintEnded(const FInputActionValue& Value);};3.2 캐릭터 소스
Section titled “3.2 캐릭터 소스”#include "MyCharacter.h"#include "EnhancedInputComponent.h"#include "EnhancedInputSubsystems.h"#include "InputMappingContext.h"#include "GameFramework/CharacterMovementComponent.h"
AMyCharacter::AMyCharacter(){ PrimaryActorTick.bCanEverTick = false;}
void AMyCharacter::BeginPlay(){ Super::BeginPlay();
// LocalPlayer의 EnhancedInputLocalPlayerSubsystem에 IMC 등록 if (APlayerController* PC = Cast<APlayerController>(GetController())) { if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PC->GetLocalPlayer())) { // Priority: 숫자가 높을수록 우선순위가 높음 Subsystem->AddMappingContext(DefaultMappingContext, 0); } }}
void AMyCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent){ Super::SetupPlayerInputComponent(PlayerInputComponent);
// Enhanced Input Component로 캐스팅 UEnhancedInputComponent* EnhancedInput = Cast<UEnhancedInputComponent>(PlayerInputComponent); if (!EnhancedInput) { return; }
// Move: Triggered (눌리는 동안 매 프레임) EnhancedInput->BindAction(IA_Move, ETriggerEvent::Triggered, this, &AMyCharacter::HandleMove);
// Look: Triggered EnhancedInput->BindAction(IA_Look, ETriggerEvent::Triggered, this, &AMyCharacter::HandleLook);
// Jump: Started (키를 누른 순간 1회) EnhancedInput->BindAction(IA_Jump, ETriggerEvent::Started, this, &AMyCharacter::HandleJump);
// Sprint: Started / Completed (누름/뗌) EnhancedInput->BindAction(IA_Sprint, ETriggerEvent::Started, this, &AMyCharacter::HandleSprintStarted); EnhancedInput->BindAction(IA_Sprint, ETriggerEvent::Completed, this, &AMyCharacter::HandleSprintEnded);}
void AMyCharacter::HandleMove(const FInputActionValue& Value){ // IA_Move의 Value Type이 Axis2D(Vector2D)인 경우 FVector2D MoveInput = Value.Get<FVector2D>();
if (Controller) { const FRotator Rotation = Controller->GetControlRotation(); const FRotator YawRotation(0, Rotation.Yaw, 0);
const FVector ForwardDir = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X); const FVector RightDir = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
AddMovementInput(ForwardDir, MoveInput.Y); AddMovementInput(RightDir, MoveInput.X); }}
void AMyCharacter::HandleLook(const FInputActionValue& Value){ // IA_Look의 Value Type이 Axis2D(Vector2D)인 경우 FVector2D LookInput = Value.Get<FVector2D>();
AddControllerYawInput(LookInput.X); AddControllerPitchInput(LookInput.Y);}
void AMyCharacter::HandleJump(const FInputActionValue& Value){ Jump();}
void AMyCharacter::HandleSprintStarted(const FInputActionValue& Value){ GetCharacterMovement()->MaxWalkSpeed = 800.f;}
void AMyCharacter::HandleSprintEnded(const FInputActionValue& Value){ GetCharacterMovement()->MaxWalkSpeed = 400.f;}4. ETriggerEvent 종류
Section titled “4. ETriggerEvent 종류”BindAction 두 번째 파라미터로 전달하는 트리거 이벤트를 선택합니다.
| ETriggerEvent | 발생 시점 |
|---|---|
Started | 입력이 시작된 첫 프레임 (키 누름 순간) |
Triggered | 입력이 활성화된 매 프레임 (키 누르는 동안) |
Ongoing | 조건을 처리 중인 매 프레임 (Tap 등 복합 트리거) |
Completed | 입력이 종료된 프레임 (키 뗌) |
Canceled | 진행 중 조건이 실패한 프레임 |
5. IMC 런타임 전환 — UI/전투 컨텍스트
Section titled “5. IMC 런타임 전환 — UI/전투 컨텍스트”// UIComponent.cpp — UI 열릴 때 전투 IMC 제거, UI IMC 추가void UUIComponent::OpenInventory(){ APlayerController* PC = Cast<APlayerController>(GetOwner()->GetInstigatorController()); if (!PC) return;
UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PC->GetLocalPlayer()); if (!Subsystem) return;
// 전투 컨텍스트 제거 Subsystem->RemoveMappingContext(CombatMappingContext);
// UI 컨텍스트 추가 (우선순위 10으로 최상위) Subsystem->AddMappingContext(UIMappingContext, 10);
PC->SetShowMouseCursor(true); PC->SetInputMode(FInputModeUIOnly());}
void UUIComponent::CloseInventory(){ APlayerController* PC = Cast<APlayerController>(GetOwner()->GetInstigatorController()); if (!PC) return;
UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PC->GetLocalPlayer()); if (!Subsystem) return;
Subsystem->RemoveMappingContext(UIMappingContext); Subsystem->AddMappingContext(CombatMappingContext, 0);
PC->SetShowMouseCursor(false); PC->SetInputMode(FInputModeGameOnly());}6. C++에서 InputAction 동적 등록
Section titled “6. C++에서 InputAction 동적 등록”에디터 에셋 없이 순수 C++로 InputAction을 생성하고 바인딩할 수 있습니다.
void AMyCharacter::SetupDynamicInput(){ UEnhancedInputComponent* EIC = Cast<UEnhancedInputComponent>(InputComponent); if (!EIC) return;
// 런타임 InputAction 생성 UInputAction* DynamicAction = NewObject<UInputAction>(this); DynamicAction->ValueType = EInputActionValueType::Boolean;
// 바인딩 EIC->BindAction(DynamicAction, ETriggerEvent::Started, this, &AMyCharacter::HandleJump);
// IMC에 동적으로 매핑 추가 UInputMappingContext* DynamicIMC = NewObject<UInputMappingContext>(this); FEnhancedActionKeyMapping& Mapping = DynamicIMC->MapKey(DynamicAction, EKeys::SpaceBar);
if (APlayerController* PC = Cast<APlayerController>(GetController())) { if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PC->GetLocalPlayer())) { Subsystem->AddMappingContext(DynamicIMC, 5); } }}7. InputAction ValueType 선택
Section titled “7. InputAction ValueType 선택”| ValueType | 사용 사례 | Get<> 타입 |
|---|---|---|
Boolean | 점프, 상호작용 (눌림/뗌) | bool |
Axis1D | 가속·감속 (단일 축) | float |
Axis2D | 이동·시점 (2D 방향) | FVector2D |
Axis3D | 3D 공간 입력 (VR 등) | FVector |
- IMC (Input Mapping Context): 물리 키 ↔ 논리 액션 매핑 그룹.
AddMappingContext/RemoveMappingContext로 런타임 전환 - InputAction: 논리적 행동 단위. 에디터에서 생성하거나 C++에서
NewObject<UInputAction>()으로 동적 생성 SetupPlayerInputComponent에서UEnhancedInputComponent로 캐스팅 후BindAction호출ETriggerEvent::Started/Triggered/Completed를 상황에 맞게 선택- 컨텍스트 우선순위(Priority)가 높은 IMC가 먼저 입력을 처리하므로 UI는 높은 값 사용