범용 UI(CommonUI)는 슬레이트/UMG(Slate/UMG) 프레임워크의 확장입니다. 범용 UI는 입력 라우팅 방법을 구현하지만 여전히 슬레이트의 기존 입력 시스템의 기본 로직을 활용합니다.
이 가이드의 각 섹션에는 범용 UI의 다양한 부분에서 기본 슬레이트/UMG 입력 시스템과 상호작용하는 방식을 수정하는 데 사용할 수 있는 몇 가지 팁과 방법이 있습니다.
입력 구성으로 애플리케이션의 UI 입력 처리 변경
현재 활성화된 위젯을 기반으로 애플리케이션의 입력 처리 방법을 변경하고자 할 때가 있습니다. 예를 들어 소셜 사이드바 또는 일시정지 메뉴가 열려 있을 때 게임에서 플레이어가 이동하지 못하게 할 수 있습니다. 이를 처리하기 위해 범용 UI 는 활성화 가능 위젯(Activatable Widgets) 의 입력 구성(Input Configs) 옵션을 지원합니다.
애플리케이션에서 입력 구성을 사용할 필요가 없고, 사용 여부와 무관하게 범용 UI의 다른 기능을 활용할 수 있습니다.
위젯에서 입력 구성 사용
입력 구성은 UIActionBindingHandle.h 에서 FUIInputConfig 구조체로 제공됩니다. 각 입력 구성은 마우스 캡처 옵션, 이동 및 보기 축 처리, 범용 UI에서 사용하는 전체 입력 모드 등 여러 입력 방법의 상태를 추적합니다.
활성화 가능 위젯을 활성화하면 UCommonActivatableWidget::GetDesiredInputConfig 를 사용하여 입력 구성을 가져옵니다. 이 함수는 기본적으로 null 입력 구성을 반환하지만 사용할 로직으로 오버라이드할 수 있습니다. 함수가 null 입력 구성을 반환할 때마다 범용 UI는 사용했던 마지막으로 유효한 입력 구성으로 돌아갑니다.
기본적으로 범용 UI는 활성화 가능 위젯으로 지정되지 않은 경우 예비로 기본 입력 구성을 적용합니다. 하지만 UCommonInputSettings 클래스에 있는 bEnableDefaultInputConfig 변수를 사용하여 이 동작을 비활성화할 수 있습니다.
위젯이 비활성화되면 범용 UI는 현재 위젯을 지원할 적절한 입력 구성 옵션 없이 중단되는 것을 방지하기 위해 사용했던 이전 입력 구성을 복원합니다. 이 구현 로직은 FActivatableTreeRoot::ApplyLeafmostNodeConfig 함수에서 찾을 수 있습니다.
UI에서 모든 위젯을 비활성화하면 범용 UI는 비활성화된 마지막 위젯의 입력 구성을 기본값으로 사용합니다. UI의 모든 위젯을 비활성화해야 하는 사용 사례의 경우 마지막으로 비활성화한 위젯이 소프트락 방지를 위해 합리적인 입력 처리 상태를 다시 적용하도록 해야 합니다.
권장 사용
입력 구성을 사용하는 경우 UI에서 표준 입력 구성 방법을 사용하지 않아야 합니다. 가상 함수 UCommonUIActionRouterBase::ApplyInputConfig 의 기본 구현은 다음 표준 UE 구성 방법을 설정 프로세스의 일부로 호출합니다.
-
APlayerController::SetIgnoreMoveInput -
UGameViewportClient::SetMouseCaptureMode -
UGameViewportClient::SetHideCursorDuringCapture
이로 인해 범용 UI의 입력 구성을 이러한 함수의 다른 호출과 혼합하면 서로를 오버라이드하여 입력 상태를 관리할 때 혼란이 발생할 수 있습니다.
입력 구성 관리를 간소화하기 위해 위젯의 열거형 값을 기반으로 주로 사용하는 입력 구성을 할당하는 기본 구현을 생성할 수 있습니다. 이에 관한 예시는 Lyra 샘플 프로젝트를 참조하세요. 위젯별로 몇 개의 고정된 비동적 입력 구성만 필요한 애플리케이션에 대한 유용한 구현을 제공합니다.
입력 처리 상태 레퍼런스
FUIInputConfig 는 여러 입력 상태로 이루어진 번들을 추적합니다. UCommonActivatableWidget::GetDesiredInputConfig 에서 입력 구성을 설정하면 위젯이 포커스될 때 입력의 작동 방식에 대한 전체 구성을 갖게 됩니다. 이러한 상태는 다음 변수를 사용하여 추적됩니다.
| 파라미터 | 타입 | 설명 |
|---|---|---|
InputMode |
열거형 / ECommonInputMode |
범용 UI의 내부 입력 모드를 설정합니다. |
MouseCaptureMode |
열거형 / EMouseCaptureMode |
범용 UI의 마우스 캡처 모드를 설정합니다. |
bHideCursorDuringViewportCapture |
부울 | true인 경우 뷰포트에서 마우스 캡처 도중 마우스 커서를 숨깁니다. |
bIgnoreMoveInput |
부울 | true인 경우 플레이어 컨트롤러가 입력 이동을 무시합니다. |
bIgnoreLookInput |
부울 | true인 경우 플레이어 컨트롤러가 보기 입력을 무시합니다. |
다음 표는 입력 모드(ECommonInputMode ) 구성에 사용 가능한 모드를 요약합니다.
| 입력 모드 | 설명 |
|---|---|
| Menu | UI에서만 입력을 수신합니다. |
| Game | 게임에서만 입력을 수신합니다. |
| All | UI와 게임 모두에서 입력을 수신합니다. |
다음 표는 마우스 캡처 모드(EMouseCaptureMode ) 구성에 사용 가능한 모드를 요약합니다.
| 마우스 캡처 모드 | 설명 |
|---|---|
| No Capture | 마우스를 캡처하지 않습니다. |
| CapturePermanently | 뷰포트가 클릭되면 마우스를 영구적으로 캡쳐하고, 캡쳐 시작 마우스 클릭은 컨슘되어 플레이어 입력에 의해 처리되지 않도록 합니다. |
| CapturePermanently_IncludingInitialMouseDown | CapturePermanently와 동일하지만 플레이어 입력이 캡처를 유발하는 마우스 버튼 누름을 처리합니다. |
| CaptureDuringMouseDown | 마우스 버튼을 누를 때 마우스를 캡처하고 마우스 버튼을 놓으면 해제합니다. |
| CaptureDuringRightMouseDown | 마우스 오른쪽 버튼을 누를 때만 캡처합니다. |
FReply를 사용하여 위젯의 입력 반응 방식 변경
FReply 는 입력 이벤트의 처리/처리되지 않은 상태를 추적합니다. 슬레이트의 대부분 입력 처리는 FReply::Handled 또는 FReply::Unhandled 결과를 반환합니다.
FReply::Handled는 입력이 대체로 다른 위젯이나 입력 시스템으로 전달되어서는 안 됨 을 나타냅니다.FReply::Unhandled는 어떠한 방식으로 입력이 사용되었더라도 추가 처리를 위해 다른 위젯이나 입력 시스템으로 전달되어야 함 을 나타냅니다.
몇 가지 일반적으로 사용되는 SWidget 입력 이벤트는 다음과 같습니다.
FReply OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent);FReply OnAnalogValueChanged(const FGeometry& MyGeometry, const FAnalogInputEvent& InAnalogInputEvent);FReply OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent);void OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent);
많은 함수(모든 함수는 아님)에서 FReply 를 반환합니다. 이러한 응답은 블루프린트에서 설정 또는 오버라이드가 가능하므로 특정 입력 타입의 처리를 중지 또는 허용해야 하는 경우 특정 FReply 반환을 시도하여 원하는 결과를 얻을 수 있습니다. 하지만 대부분의 기본 FReply 결과는 잘 디자인된 위젯 또는 위젯 세트에 충분할 것입니다. 커스텀 FReply 처리는 슬레이트의 위젯을 작업할 때 문제가 되는 경우가 많습니다.
FReply 입력 라우팅의 흐름을 보여주는 차트. 입력은 플랫폼의 자체 입력 이벤트로 시작하여 슬레이트 애플리케이션으로 전달됩니다. 슬레이트 애플리케이션은 이를 위젯으로 보내고, 위젯은 FReply를 사용하여 입력이 Handled 또는 Unhandled 상태인지 여부를 결정합니다. 입력이 Handled 상태이거나 모든 위젯이 확인될 때까지 반복됩니다.
FReply 세팅
FReply 는 입력 이벤트의 Handled 또는 Unhandled 상태를 추적하지만 FReply 내에서 다음 멤버를 통해 추가 데이터를 추적할 수 있습니다.
| 파라미터 | 설명 |
|---|---|
| CaptureMouse | 시스템에 특정 위젯으로 모든 마우스 이벤트를 전달하도록 요청합니다. |
| ClearUserFocus | 시스템에 사용자 포커스 지우기를 요청합니다. |
| ReleaseMouseCapture | 시스템에 마우스 캡처 해제를 요청합니다. |
| SetUserFocus | 시스템에 사용자의 포커스를 제공된 위젯으로 설정하도록 요청합니다. |
| SetNavigation | 시스템에 지정된 대상으로의 내비게이션을 시도하도록 요청합니다. |
위의 목록은 완전한 목록으로, 표시될 메서드의 종류를 보여주는 역할을 합니다. 전체 목록은 FReply 관련 공식 C++ API를 참조하세요.
FReply::CaptureMouse 및 FReply::SetUserFocus 와 같은 일부 이벤트는 타깃 위젯을 포함한 추가 인수를 가져옵니다.
UMG 또는 슬레이트에 익숙하다면 이러한 메서드가 비슷해 보일 수 있습니다. 하지만 이는 FReply 네임스페이스에 있으며, 슬레이트에서 FReply 를 처리할 때 발생하는 동작을 수정할 수 있습니다. FReply 에서 이러한 메서드를 호출하면 FReply 외부의 동등한 메서드를 호출함으로써 손쉽게 복제할 수 없는 약간 다른 동작이 나올 수 있습니다.
FReply를 언제 설정합니까?
FReply 사용 시기에 관한 예시로 키를 입력할 때 위젯 포커스를 설정하거나 지워야 한다고 상상해 보세요. 보통은 키 입력 핸들러의 FSlateApplication 에서 관련 함수를 직접 호출하여 위젯 포커스 변경을 시도할 수 있습니다.
이 접근 방식은 모든 시나리오에서, 특히 입력 라우팅을 사용할 때에는 작동하지 않을 수 있는데, 현재 위젯에서 입력이 처리 중인 동안 포커스 변경 또는 지우기를 시도하기 때문입니다. 이 입력 흐름은 원치 않는 동작으로 이어질 수 있습니다.
대신 슬레이트를 사용하여 입력을 완전히 처리하고, 입력 이벤트 반응, 즉 FReply 사용 등의 변경 사항을 처리하는 것이 좋습니다.
원래 FReply API에서 제어 또는 노출되는 상태는 FReply 만을 사용하여 설정되어야 했습니다. 하지만 너무 제한적인 것으로 입증되어서 변경되었고, 따라서 이 워크플로는 권장 가이드라인 그 이상입니다. 선호하는 워크플로이므로 강력하게 권장됩니다.
UI에서 내비게이션 커스터마이징
이 섹션에서는 범용 UI에서 내비게이션 커스터마이징 가이드라인과 옵션을 제공합니다.
내비게이션 구성
내비게이션 구성은 범용 UI와 직접 연관되지 않지만 이를 이해하면 입력 처리 이해에 도움이 됩니다.
슬레이트는 범용 UI의 활성화 여부와 무관하게 기본 내비게이션을 지원합니다. 내비게이션 구성(Navigation Configs), 즉 FNavigationConfig 을 사용하면 기본 방향에 어떤 키를 매핑할지 결정합니다.
- 왼쪽(Left)
- 오른쪽(Right)
- 위(Up)
- 아래(Down)
- 다음(Next)
- 이전(Previous)
수동 내비게이션 구성은 슬레이트에서 기본 내비게이션을 사용하는 데 있어 필요하지 않습니다.
내비게이션 구성을 설정하려면 FSlateApplication::SetNavigationConfig 를 호출합니다. 대체로 FNavigationConfig 에서 파생된 커스텀 내비게이션 구성을 사용하여 이 함수를 호출합니다. 예를 들어 사용자가 WASD 키로 UI와 상호작용하고자 한다면 여기에서 시작하는 것이 좋습니다.
또한 FSlateUser::SetUserNavigationConfig 를 호출하여 사용자별 기반으로 내비게이션 구성을 설정할 수 있습니다.
수동으로 내비게이션 제어
내비게이션 이벤트 발생 시 어떻게 될지를 수동으로 설정하려면 UMG에서 위젯을 선택하고 디테일(Details) 패널에 있는 내비게이션(Navigation) 섹션을 찾아봅니다. 이 섹션에는 각 기본 방향에 대한 옵션이 있습니다.
옵션은 아래 표에서 자세히 설명합니다.
| 내비게이션 컨트롤 옵션 | 설명 |
|---|---|
| 탈출(Escape) | 해당 방향으로의 이동 지속을 허용하며, 자동으로 다음 내비게이션 가능한 위젯을 검색합니다. |
| 명시(Explicit) | 특정 위젯으로 이동합니다. |
| 래핑(Wrap) | 한쪽 끝에서 더 나가면 다시 반대 끝으로 나와 빙빙 돌게 됩니다. 내비게이션을 시도하면 이 상태에서 탈출하게 됩니다. |
| 중지(Stop) | 이 방향의 이동을 중지합니다. |
| 커스텀(Custom) | 사용자 코드로 처리되는 커스텀 내비게이션입니다. |
| 커스텀 바운더리(CustomBoundary) | 바운더리에 걸린 경우 사용자 코드로 처리되는 커스텀 내비게이션입니다. |
예를 들어 다음은 명시(Explicit) 가 유용한 옵션일 수 있는 사용 사례입니다.
이 예시에서 상단 및 하단 버튼은 왼쪽의 포커스된 버튼으로 수직으로 오버랩되지 않습니다. 오버랩이 없기 때문에 오른쪽(Right)을 내비게이션하는 경우 언리얼은 가장 오른쪽에 있는 버튼을 포커스합니다. 오른쪽을 상단 버튼으로 내비게이션하고자 하는 경우 내비게이션 세팅을 구성할 수 있습니다.
명시(Explicit) 내비게이션을 TopButton 위젯으로 설정하면서 사용자가 오른쪽을 누를 때마다 이 위젯이 대신 포커스됩니다.
위젯을 명시 내비게이션 타깃으로 설정하려면 수동으로 이름을 지정해야 합니다. 이를 통해 내비게이션 동작을 장시간 유지할 수 있습니다.
활성화 가능 위젯과 액션 바인딩
이 섹션에서는 UI에 대한 활성화 가능 위젯과 바운드 입력 액션의 동작을 커스터마이징하는 방법에 관한 정보를 제공합니다.
활성화 시 활성화 가능 위젯의 포커스 설정
활성화 가능 위젯을 활성화할 때마다 UCommonActivatableWidget::GetDesiredFocusTarget 함수가 호출되어 사용자 입력 시 범용 UI가 포커스해야 하는 위젯을 선택합니다.
GetDesiredFocusTarget 의 커스텀 버전을 구현하지 않으면 범용 UI에서 위젯이 활성화 및 비활성화될 때 포커스할 위치를 파악하는 데 어려움이 있을 수 있습니다. 이런 이유로 활성화 가능 위젯에서 이 함수를 항상 구현하는 것을 권장합니다.
Lyra 샘플 프로젝트에서 각각의 활성화 가능 위젯 클래스에는 원하는 포커스 타깃을 가져오는 데 사용할 메서드를 결정하는 커스텀 열거형 타입이 있습니다. 기본 포커스 결정에 고정된 비동적 메서드를 사용하는 대부분 메뉴에 비슷한 구현을 권장합니다.
입력 액션 트리거 발생 시 변경
액션 바인딩에 대해 FBindUIActionArgs 를 생성할 때 FBindUIActionArgs::KeyEvent 를 이벤트를 트리거해야 하는 액션 타입(예: IE_Released )으로 설정합니다.
범용 UI 콘솔 변수 레퍼런스
다음 콘솔 변수 표를 사용하여 범용 UI의 작동 방식을 구성하고 디버깅 정보를 얻을 수 있습니다.
| CVar | 설명 |
|---|---|
| CommonUI.bDumpInputTypeChangeCallstack | true인 경우 입력 타입이 변경될 때 범용 UI가 콜 스택을 덤핑합니다. 입력 타입이 빠르게 변경된 것 같을 때 디버깅에 유용합니다. |
| CommonInput.ShowKeys | 현재 입력 디바이스에 대한 키를 표시할지 여부를 토글합니다. |
| CommonInput.EnableGamepadPlatformCursor | 게임패드 입력 도중 커서를 활성화할지 여부를 토글합니다. |
| UseTransparentButtonStyleAsDefault | true인 경우 CommonButtonBase 의 SButton 에 대한 기본 버튼 스타일(Button Style) 이 NoBorder 로 설정되고, 투명 배경을 가지며 패딩이 없습니다. |
| Mobile.EnableUITextScaling | 모바일 UI 텍스트 스케일링을 활성화합니다. |
| ActionBar.IgnoreOptOut | true인 경우 바운드 액션 바(Bound Action Bar) 에 구성 여부와 무관하게 바인딩이 표시됩니다. |
| CommonUI.AlwaysShowCursor | true인 경우 범용 UI가 현재 입력 구성과 무관하게 항상 마우스 커서를 표시합니다. |
| CommonUI.VideoPlayer.PreviewStepSize | CommonVideoPlayer의 시간 단계 수입니다. |