[Unreal] 향상된 입력 InputMappingContext 사용하기
언리얼 엔진의 버전이 4 -> 5로 업그레이드 됨에 따라 향상된 입력이 추가되었습니다.
5.0 버전에서는 이전 입력 시스템을 그대로 사용할 수 있었지만, 5.3버전을 사용하려고 보니 기존 입력 시스템에서 권장하지 않는 모습을 보였습니다.
이 글에서는 향상된 입력을 사용해서 캐릭터를 앞뒤좌우로 이동하는 방법을 소개합니다.
먼저 입력 맵핑 컨텍스트와 입력 액션 두가지를 만들어줍니다.
입력 맵핑 컨텍스트는 입력 액션을 참고하여 세부사항을 설정하고 키를 맵핑할 수 있도록 도와줍니다.
이름은 자유롭게 설정하고 먼저 생성한 InputAction을 수정합니다.
값 타입을 Axis2D (Vector2D)로 설정합니다.
WASD와 같은 입력을 사용하기 위해 X축과 Y축을 사용합니다.
또한 키가 눌렸을 경우에 지속적인 입력이 들어와야하므로 눌림이 아닌 다운으로 설정해야합니다.
또한 W와 S가 같이 눌려있을 경우 값을 상쇄시키기 위해 누적행동을 Cumulative로 설정합니다.
이후 InputMappingContext를 설정합니다.
이 부분은 조금 복잡해보이지만 한 번 학습하고 나면 다른 맵핑도 충분히 응용가능합니다.
이해를 돕는 글
- Axis2D(Vector2D)의 값은 X와 Y축의 값을 사용할 수 있습니다.
- 이전 입력 시스템에서는 S나 A 키에 대응하는 Axis 값을 -1로 설정하면서 반대 값을 가져올 수 있었습니다.
- 하지만 X축과 Y축을 한번에 설정하기가 어려워 MoveForward나 MoveRight같은 값을 사용했습니다.
- 입력 맵핑 컨텍스트에서는 하나의 입력 액션으로 앞,뒤,좌,우 움직임을 설정할 수 있습니다.
- 모디파이어를 이용해 입력되는 값을 조정하는 것이 그 방법입니다.
- 조이스틱이 아닌 키보드의 입력은 단 하나의 값만 조절할 수 있습니다.
- 입력 액션에 따라서 등록된 키를 누르면 0또는 1의 값이 입력되는데, 제공된 모디파이어를 이용해 설정할 수 있습니다.
- 위 설정에서 모디파이어가 없는 경우 X,Y,Z 값 중 X값에만 값이 입력됩니다.
- 그러므로 'D' 키에서는 X축 0~1값만 사용하기 때문에 값을 수정할 필요가 없습니다.
- 반대 키 'A'의 경우 X축의 0~ -1값을 사용합니다. 그렇기 때문에 부정 모디파이어를 이용하여 1을 -1로 변경해줄 수 있습니다.
- 'W'키의 경우 XYZ 축에서 Y축에 입력되어야 합니다.
- 그러므로 스위즐 입력축값을 YXZ값으로 변경해줌으로 매핑된 키값이 Y에게 입력값(0~1)을 설정해줄 수 있습니다.
- 'S'키의 경우 'W'키와 비슷하게 Y축에 설정되어야하고 1 대신 -1 값을 받아야하므로 스위즐과 함께 부정 모디파이어도 설정해야합니다.
방향 입력
입력 모디파이어의 좋은 사용 사례는 단일 입력 액션을 사용하는 2차원 방향 입력입니다. 마우스나 게임패드의 아날로그 스틱으로 2차원 이동을 읽는 것은 최소한 두 개의 축을 지원하는 입력 액션을 만들고 입력 매핑 컨텍스트에 적절한 입력을 추가하는 간단한 문제입니다.
향상된 입력은 키보드의 방향키나 많이 사용하는 'WASD' 키 환경설정 같은 1차원 소스의 입력을 지원합니다. 올바른 입력 모디파이어를 적용하여 이러한 컨트롤 체계를 완성할 수 있습니다. 구체적으로는 부정(Negate) 을 사용하여 일부 키를 음수로 등록하고 입력 축 값 스위즐(Swizzle Input Axis Values) 을 사용하여 일부 키를 기본 X축 대신 Y축으로 등록합니다.
설정이 완료된 맵핑 컨텍스트와 입력 액션은 사용하기 위해 등록해주는 과정이 필요합니다.
C++ 코드를 이용해 아래 이미지와 같이 간편하게 설정할 수 있도록 작업합니다.
// MyCharacter.h
// 헤더파일에서 입력맵핑컨텍스트와 입력 액션을 선언합니다.
// 입력 액션이 TMap으로 설정된 이유는 추가될 입력 액션을 쉽게 찾아 사용하기 위함입니다.
protected :
/* Player Input Mapping Context */
UPROPERTY(EditAnywhere, Category = "Input")
TObjectPtr<UInputMappingContext> InputMapping;
/* Player Input Action */
UPROPERTY(EditAnywhere, Category = "Input")
TMap<FString, TObjectPtr<UInputAction>> InputActions;
// 함수 선언
virtual void BeginPlay() override;
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
// 이전 함수는 void OnMoveForward(float InAxis)와 같이 선언되었습니다.
// 향상된 입력을 사용하기 위해서는 FInputActionInstance를 사용합니다.
void OnMove(const FInputActionInstance& Instance);
// MyCharacter.cpp
void APlayerBase::BeginPlay()
{
Super::BeginPlay();
// 맵핑 컨텍스트를 등록하는 과정
APlayerController* PlayerController = Cast<APlayerController>(Controller);
if (PlayerController != nullptr)
{
UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem< UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer());
if (Subsystem != nullptr)
{
Subsystem->AddMappingContext(InputMapping, 0);
}
}
}
void APlayerBase::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
// 향상된 입력으로 캐스팅합니다.
UEnhancedInputComponent* input = Cast<UEnhancedInputComponent>(PlayerInputComponent);
// 이전 입력 시스템의 바인딩과 약간의 차이가 있습니다.
input->BindAction(InputActions.FindRef("Move"), ETriggerEvent::Triggered, this, &APlayerBase::OnMove);
}
void APlayerBase::OnMove(const FInputActionInstance& Instance)
{
FVector2D moveDirection = Instance.GetValue().Get<FVector2D>();
AddMovementInput(GetActorRightVector(), moveDirection.X);
AddMovementInput(GetActorForwardVector(), moveDirection.Y);
}
추가 정보
프로젝트 셋팅 -> 엔진 -> 향상된 입력에서 기본 맵핑 컨텍스트를 설정할 수 있습니다.
향상된 입력을 사용하려면 입력 플러그인을 활성화합니다. 5.3버전에서는 기본적으로 사용이 가능합니다.
복잡한 입력 처리나 런타임 제어 리매핑 등 보다 고급 입력 기능이 필요한 언리얼 엔진 5 (UE5) 프로젝트에 적합한 향상된 입력(Enhanced Input) 은 개발자에게 업그레이드 경로와 언리얼 엔진 4 (UE4) 기본 입력 시스템과의 하위 호환성을 제공합니다.
이 플러그인은 방사상 데드존, 조화된 액션, 컨텍스트에 따른 입력 및 우선순위 지정뿐 아니라 에셋 기반 환경에서 원시(raw) 입력 데이터의 자체 필터링 및 처리 확장 등의 기능을 구현합니다.
다이내믹 및 컨텍스트에 따른 입력 매핑
향상된 입력을 사용하면 런타임 시 플레이어에 대한 매핑 컨텍스트(Mapping Contexts) 를 추가하고 제거할 수 있습니다. 이를 통해 수많은 액션(Action) 을 더 쉽게 관리할 수 있습니다. 플레이어의 현재 스테이트에 따라 특정 입력 동작 방식을 변경할 수 있습니다.
향상된 입력 시스템은 입력 액션(Input Actions) , 입력 매핑 컨텍스트(Input Mapping Contexts) , 입력 모디파이어(Input Modifiers) , 그리고 입력 트리거(Input Triggers) 이렇게 4가지 주요 콘셉트로 이루어져 있습니다.
입력 액션
입력 액션 은 향상된 입력 시스템과 프로젝트 코드 간의 통신 링크입니다. 입력 액션은 데이터 에셋이라는 점만 다를 뿐, 액션 및 축(Axis) 매핑 이름과 개념적으로 같습니다. 각 입력 액션은 '웅크리기'나 '무기 발사' 같은 사용자가 할 수 있는 행동을 나타내야 합니다. 입력 액션의 스테이트가 변경될 때 블루프린트 또는 C++에 입력 리스너(Input Listeners) 를 추가할 수 있습니다.
입력 액션은 여러 타입이 될 수 있으며, 타입에 따라 액션의 동작이 결정됩니다. 단순한 부울 액션을 만들 수도 있고 더욱 복잡한 3D 축을 만들 수도 있습니다. 액션 타입이 그 값을 결정합니다. 부울 액션은 단순한 bool 값을 갖고, Axis1D 는 float 값을, Axis2D 는 FVector2D , 그리고 Axis3D 는 전부 FVector 입니다.
트리거 스테이트
트리거 스테이트(Trigger State) 는 시작됨(Started), 진행 중(Ongoing), 트리거됨(Triggered), 완료됨(Completed) 및 취소됨(Canceled) 같이 액션의 현재 스테이트를 나타냅니다. '트리거됨' 스테이트를 자주 사용할 것입니다. C++과 블루프린트 모두에서 특정 스테이트에 바인딩할 수 있습니다.
- 트리거됨: 액션이 트리거되었습니다. 즉, 모든 트리거 요구 사항 평가를 완료했다는 뜻입니다. 예를 들어, 사용자가 키를 놓으면 '키 누르고 떼기(Press and Release)' 트리거가 전송됩니다.
- 시작됨: 트리거 평가를 시작한 이벤트가 발생했습니다. 예를 들어, '두 번 탭(Double tap)' 트리거를 처음 누르면 '시작됨' 스테이트가 한 번 호출됩니다.
- 진행 중: 트리거를 여전히 처리 중입니다. 예를 들어, 지정된 기간이 끝나기 전에 사용자가 버튼을 누르고 있는 동안에는 '길게 누르기(Press and hold)' 액션이 진행 중입니다. 이 이벤트는 트리거에 따라 입력 값을 수신하면 작업이 평가되는 동안 틱마다 발동됩니다.
- 완료됨: 트리거 평가 프로세스가 완료되었습니다.
- 취소됨: 트리거링이 취소되었습니다. 예를 들어, 사용자가 '길게 누르기' 액션이 트리거되기 전에 버튼을 놓는 경우가 있습니다.
입력 매핑 컨텍스트
입력 매핑 컨텍스트 는 플레이어가 처할 수 있는 특정 컨텍스트를 나타내는 입력 액션 컬렉션으로, 주어진 입력 액션의 트리거 규칙을 설명합니다. 각 사용자에게 매핑 컨텍스트를 동적으로 추가하거나 제거하거나 우선순위를 지정할 수 있습니다.
입력 매핑 컨텍스트를 생성하려면 컨텍스트 브라우저 를 우클릭한 다음, 입력(Input) 옵션을 펼치고 입력 매핑 컨텍스트(Input Mapping Context) 를 선택합니다.
입력 매핑 컨텍스트의 기본 구조는 최상위 레벨에 입력 액션 목록이 있는 계층구조입니다. 입력 액션 레벨 아래에는 키, 버튼, 이동 축과 같이 각 입력 액션을 트리거할 수 있는 사용자 입력 목록이 있습니다.
최하위 레벨에는 각 사용자 입력에 대한 입력 트리거와 입력 모디파이어 목록이 포함되어 있습니다. 이를 사용하여 입력 원시 값의 필터링 방식이나 처리 방식, 그리고 최상위 계층구조에서 입력 액션을 구동하기 위해 충족해야 하는 제한 사항을 결정할 수 있습니다.
향상된 입력 로컬 플레이어 서브시스템(Enhanced Input Local Player Subsystem)을 통해 이러한 컨텍스트를 하나 이상 로컬 플레이어에게 적용할 수 있으며, 컨텍스트의 우선순위를 지정하여 같은 입력을 사용하려는 여러 액션 간의 충돌을 해결할 수 있습니다.
여기에서 입력 액션 바인딩에 대한 실제 키를 구현하고 각 액션에 대한 추가 트리거 또는 모디파이어를 지정합니다. 향상된 입력 서브시스템에 입력 매핑 컨텍스트를 추가할 때 우선순위를 지정할 수도 있습니다. 같은 입력 액션에 여러 컨텍스트를 매핑한 경우, 입력 액션이 트리거되면 가장 우선순위가 높은 컨텍스트가 고려되고 다른 컨텍스트는 무시됩니다.
예를 들어, 수영하고 걷고 운전하는 캐릭터에 여러 입력 매핑 컨텍스트를 줄 수 있습니다. 하나는 사용할 수 있으며 항상 동일한 사용자 입력에 매핑되는 일반 액션이며, 다른 하나는 각각의 개별 이동 모드에 대한 것입니다.
개발자는 비히클 관련 입력 액션을 별도의 입력 매핑 컨텍스트에 배치할 수 있으며, 이 입력 매핑 컨텍스트는 차량에 탑승할 때 로컬 플레이어에 추가되고 비히클에서 내릴 때 로컬 플레이어에게서 제거됩니다.
이렇게 하면 최적화에 도움이 되며 부적절한 입력 액션이 실행되지 않도록 하여 버그를 방지할 수 있습니다. 또한, 상호 배타적인 입력 매핑 컨텍스트를 사용하는 것도 입력 충돌 방지에 도움이 되는데, 사용자 입력이 다른 입력 액션에 사용될 때 그 입력이 실수로 잘못된 액션을 트리거하지 않기 때문입니다.
입력 모디파이어
입력 모디파이어 는 입력 트리거로 보내기 전에 UE 에서 받는 원시 입력 값을 변경하는 프리 프로세서입니다. 향상된 입력 플러그인에는 축의 순서를 변경하고, '데드존'을 구현하고, 축 입력을 월드 스페이스로 변환하는 등 다양한 작업을 수행하기 위한 다양한 입력 모디파이어가 있습니다.
입력 모디파이어는 민감도 세팅을 적용하거나 여러 프레임에 걸쳐 입력을 스무딩하거나 플레이어 스테이트에 따라 입력 동작 방식을 변경하는 데 유용합니다. 자체 모디파이어를 만들 때 UPlayerInput 클래스에 액세스하므로 보유한 플레이어 컨트롤러(Player Controller)에 액세스하고 원하는 게임 스테이트를 가져올 수 있습니다.
C++나 블루프린트에서 UInputModifier 클래스의 서브클래스를 만들고 ModifyRaw_Implementation 함수를 오버라이드하여 자신만의 입력 모디파이어를 만들 수 있습니다.
또한, Input Modifier 를 부모로 두고 Blueprint Child Class 를 생성하여 자신만의 입력 모디파이어를 생성할 수도 있습니다.
'Unreal > Manual' 카테고리의 다른 글
Unreal Editor 에서 Debug용 도형 그리기 (0) | 2024.03.10 |
---|---|
Unreal Editor Module 만들기 (0) | 2024.03.10 |
Unreal BehaviorTree에서 Random Selector Composite 만들기 (0) | 2024.02.14 |
Unreal Animation Instance, 캐릭터의 속도와 방향 구하기 (1) | 2024.02.08 |
Unreal 인공지능 AIController 구성하기 (3) | 2024.02.07 |