https://ctdidier27.medium.com/common-ui-plugin-ue5-b12050bf1fc0
- 화면을 그대로 유지하면서 Overlay 되는 UI를 노출하고, 화면입력을 막고 싶은 경우
- 플랫폼 별로 UI Element를 다르게 관리하고 싶을 때
- Popup들의 버튼을 누를 시 UI가 특정 상태가 되도록 흐름을 제어하고 싶을 때
- 키보드나 콘솔 컨트롤러의 방향키로 UI 선택을 이동시키고 싶을 때(Cardinal Navigation)
핵심 개념
Input Routing
- Selective Interaction을 구현하기 위해 채택한 방식
- 입력을 수신하는 조건과 시기를 컨트롤 할 수 있다.
- 예를 들어, 서로 다른 Widget에 버튼 별 Input을 분배해서 배치할 수 있다.
- 이는 입력이 각 Widget에서 처리되는 것이 아니라 공용 Class에 전달되어 일괄처리 되기 때문이다.
Node
- Common UI는 Widget을 Node로 변환해 Visual Hierarchy에 따라 상위에 Rendering 된 Widget의 입력을 Route한다.
- 몇 가지 예외를 제외하고, 대부분의 Common UI는 Slate의 Hierarchy와 동일하게 구성된다.
- 각 Tree는 Viewport에 직접 배치 된 Widget을 Root Node로,
Button과 같은 개별 UI Element를 Leaf Node로 취급하여 구성된다.
- 각 Tree는 Viewport에 직접 배치 된 Widget을 Root Node로,
- Common UI는 Tick당 1번씩 다른 Tree보다 상단에 Render 된 Tree를 탐색해 Root Node로 Input을 Route한다.
- 그럼 Root Widget은 Input을 처리할 수 있는 첫번째 Leaf Node에 입력을 전달한다.
- 입력을 전달 받은 Leaf Node는 이를 처리하거나, 필요하다면 다른 곳으로 재전달한다.
ActivatableWidget
- Common UI 중 Input 처리를 위해 Node로 변환되고, 이를 수신할 수 있는 Widget
- Input 수신 시 Active 상태로 간주한다.
- Activatable Widget은 다음 기능을 제공한다.
- Input 수신 가능 여부(Active/Inactive) 상태 토글
- 같은 Tree 내 다른 Activatable Widget에 Input 전달
- 뒤로가기 등 특정 상황에서 Inactivate
- 이 Widget을 이용해 현재 Input을 수신중인 Overlay UI가 닫힐 경우,
적절한 Element로 복구해주는 기능을 작업할 수 있다.- Input은 항상 최상단에 Layer에만 Route 되기에 하단 Layer의 Widget도 문제 없이 Active 상태로 둘 수 있다.
- 이 때 상단 Layer가 닫히면 자연스럽게 하단 Layer에 Input이 Route 된다.
사용법
Viewport Configure
- Edit -> Project Settings -> Engine -> General Settings으로 이동
- Game Viewport Client Class를 CommonGameViewportClient 혹은 이를 상속받은 Custom Class로 설정
Create InputActionDataTable
- 한가지 잊지 말아야 할 점이 있다.
- CommonUI InputAction DataTable은 Project Setting, Advanced Input System에 사용하는 것과 무관하다.
- 오직 UI Input 관리에만 사용된다.
- Content Browser 영역 우클릭 -> Miscellaneous -> CommonUI ActionInput Data Table선택
- 위와 같이 Row를 추가해 Input을 설정한다.
- 이렇게 추가된 InputAction은 CommonUI Widget에서 Mapping할 수 있다.
- 위 사진은 CommonButtonBase의 Class Defaults에서 DataTable과 RowName을 통해
InputAction을 Button에 Mapping 한 예시이다.
- 위 사진은 CommonButtonBase의 Class Defaults에서 DataTable과 RowName을 통해
- 좀 더 용이하게 관리하려면 관련된 Action들을 하나의 DataTable에서 작업하여 그룹화 하는 것이 좋다.
CommonInputActionDataBase
더보기
USTRUCT(BlueprintType)
struct COMMONUI_API FCommonInputActionDataBase : public FTableRowBase
{
GENERATED_BODY()
FCommonInputActionDataBase();
/** User facing name (used when NOT a hold action) */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "CommonInput")
FText DisplayName;
/** User facing name used when it IS a hold action */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "CommonInput")
FText HoldDisplayName;
/** Priority in nav-bar */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "CommonInput")
int32 NavBarPriority = 0;
protected:
/**
* Key to bind to for each input method
*/
UPROPERTY(EditAnywhere, Category = "CommonInput")
FCommonInputTypeInfo KeyboardInputTypeInfo;
/**
* Default input state for gamepads
*/
UPROPERTY(EditAnywhere, Category = "CommonInput")
FCommonInputTypeInfo DefaultGamepadInputTypeInfo;
/**
* Override the input state for each input method
*/
UPROPERTY(EditAnywhere, Category = "CommonInput", Meta = (GetOptions = "CommonInput.CommonInputBaseControllerData.GetRegisteredGamepads"))
TMap<FName, FCommonInputTypeInfo> GamepadInputOverrides;
/**
* Override the displayed brush for each input method
*/
UPROPERTY(EditAnywhere, Category = "CommonInput")
FCommonInputTypeInfo TouchInputTypeInfo;
};
- DisplayName
- 해당 InputAction의 이름
- Navigation Bar가 있는 경우 해당 Bar에 표시된다.
- HoldDisplayName
- 버튼 Hold 동작이 필요한 InputAction의 이름
- NavBarPriority
- Navibation Bar Action을 왼쪽에서 오른쪽으로 Sort할 때 사용하는 Priority
- KeybaordInputTypeInfo
- 마우스 및 키보드 Action의 InputType
- DefaultGamepadInputTypeInfo
- Gamepad Action의 InputType
- GamepadInputOverrides
- 특정 Gamepad에서 해당 Action에 사용되는 키
- 콘솔 플랫폼 별 버튼 Override에 유용하다.
- Nintendo Switch Gamepad의 앞뒤 버튼을 바꾸는 것
- TouchInputTypeInfo
- Touch Interface Action의 InputType
CommonInputTypeInfo
더보기
USTRUCT(BlueprintType)
struct COMMONUI_API FCommonInputTypeInfo
{
GENERATED_USTRUCT_BODY()
FCommonInputTypeInfo();
private:
/** Key this action is bound to */
UPROPERTY(EditAnywhere, Category = "CommonInput")
FKey Key;
public:
/** Get the input type key bound to this input type, with a potential override */
FKey GetKey() const;
/** Get the input type key bound to this input type, with a potential override */
void SetKey(FKey InKey)
{
Key = InKey;
};
/** EInputActionState::Enabled means that the state isn't overriden and the games dynamic control will work */
UPROPERTY(EditAnywhere, Category = "CommonInput")
EInputActionState OverrrideState;
/** Enables hold time if true */
UPROPERTY(EditAnywhere, Category = "CommonInput")
bool bActionRequiresHold;
/** The hold time in seconds */
UPROPERTY(EditAnywhere, Category = "CommonInput", meta = (EditCondition = "bActionRequiresHold", ClampMin = "0.0", UIMin = "0.0"))
float HoldTime;
/**
* Time (in seconds) for hold progress to go from 1.0 (completed) to 0.0.
* If the hold interaction was interrupted, then hold progress starts to roll back decreasing its value.
* Set to 0.0 to disable the rollback functionality.
*/
UPROPERTY(EditAnywhere, Category = "CommonInput", meta = (EditCondition = "bActionRequiresHold", ClampMin = "0", UIMin = "0", ClampMax = "10.0", UIMax = "10"))
float HoldRollbackTime;
/** Override the brush specified by the Key Display Data */
UPROPERTY(EditAnywhere, Category = "CommonInput")
FSlateBrush OverrideBrush;
};
- Key
- Bind 될 Input Key
- OverrideState
- Input 및 Callback 호출 여부의 상태를 담당
- bActionRequiredsHold
- Input이 Hold로 작동되어야 하는지 여부
- HoldTime
- Input이 Hold로 작동 되어야 할 때, Hold해야 하는 시간
- HoldRollbackTime
- Hold가 작동하고 나서 완전히 비활성화 상태로 되돌아갈 때까지의 시간.
- OverrideBrush
- Key Display Data에서 정의된 Brush로 Override
EInputActionState
더보기
UENUM(BlueprintType)
enum class EInputActionState : uint8
{
/** Enabled, will call all callbacks */
Enabled,
/** Disabled, will call all the disabled callback if specified otherwise do nothing */
Disabled,
/** The common input reflector will not visualize this but still calls all callbacks. NOTE: Use this sparingly */
Hidden,
/** Hidden and disabled behaves as if it were never added with no callbacks being called */
HiddenAndDisabled,
};
- Enabled
- Input이 활성화 되어 있음
- Callback이 호출 됨
- Disabled
- Disable Callback이 선언되어 있는 경우 이를 호출 함
- 그 외의 모든 Callback이 반응하지 않음
- Hidden
- Reflector가 시각적으로 보이지는 않지만 Callback이 호출 됨.
- 자주 사용하지 않을 것을 권장 함.
- HiddenAndDisabled
- Reflector가 시각적으로 보이지 않고, Callback도 동작하지 않음.
Default Navigation Action Configure
- Unreal Engine에서 Native Navigation을 지원하지만,
CommonUI을 사용하면 CommonUIInputData를 기반으로 한 별도의 Navigation이 정의되어야 한다.
- Create New Plueprint Class에서 CommonUIInputData를 선택해 BP 생성
- 생성한 파일 내에 CommonUI InputActionDataTable과 Row를 지정하여 Navigation을 지정
- HoldData의 경우 CommonUIHoldInputData를 기반으로 신규 BP를 생성한 뒤, 해당 파일을 연결해줘야 한다.
- Click Action
- 버튼이나 기타 상호작용 가능한 Element를 Highlight 할 때 Mouse Click을 대체
- Back Action
- 현재 Menu에서 이전 Menu로 이동할 때 공통으로 사용
- Project Settings -> Game -> Common Input Settings의 InputData에 연결한다.
- 설정 시, 지정된 Asset을 Default Navigation에 사용한다.
Bind Controller Data per Platform
- Controller Data Asset은 Key-Action을 UI Elemnt에 연결해준다.
- 각 Controller Data Asset은 Input Type, Gamepad, Platform과 연관되어 있다.
- CommonUI는 이 정보를 이용해 현재 Platform과 Input Type을 기반으로
올바른 Platform 별 UI Element를 자동으로 사용한다.- 이를 통해 다수의 Input Type이나 고유한 Gamepad를 지원하는 Platform에서
User Input을 올바른 GamePad에 전달하거나, Runtime에서 UI Elemnt를 교체할 수도 있다.
- 이를 통해 다수의 Input Type이나 고유한 Gamepad를 지원하는 Platform에서
- Create New Blueprint Class에서 CommonInputBaseControllerData를 선택해 생성
- 생성한 모든 Controller Data Asset은
Project Settings -> Game -> Common Input Settings의 Platform Input에 추가되어야 한다.- Platform Input에서 입력하는 Default Gamepad Name은
Controller Data Asset들의 Gamepad Name 필드들로만 입력되어야 한다. - 이 값이 일치하지 않으면 Controller Data를 인식하지 못하고 Icon이 표시되지 않는다.
- Platform Input에서 입력하는 Default Gamepad Name은
- 보통은 한 Platform의 Controller Data Array에 여러 개의 Gamepad Data를 작성해 다양한 컨트롤러를 지원한다.
- 만약 별도의 Controller에 대한 게임플레이 지원을 해야 한다면,
Gamepad Data를 새로 작성해 Controller Data에 추가하면 된다.
- 만약 별도의 Controller에 대한 게임플레이 지원을 해야 한다면,
CommonInputBaseControllerData
더보기
/* Derive from this class to store the Input data. It is referenced in the Common Input Settings, found in the project settings UI. */
UCLASS(Abstract, Blueprintable, ClassGroup = Input, meta = (Category = "Common Input"))
class COMMONINPUT_API UCommonInputBaseControllerData : public UObject
{
GENERATED_BODY()
public:
virtual bool NeedsLoadForServer() const override;
virtual bool TryGetInputBrush(FSlateBrush& OutBrush, const FKey& Key) const;
virtual bool TryGetInputBrush(FSlateBrush& OutBrush, const TArray<FKey>& Keys) const;
virtual void PreSave(FObjectPreSaveContext ObjectSaveContext) override;
virtual void PostLoad() override;
private:
#if WITH_EDITORONLY_DATA
UPROPERTY(Transient, EditAnywhere, Category = "Editor")
int32 SetButtonImageHeightTo = 0;
#endif
public:
UPROPERTY(EditDefaultsOnly, Category = "Default")
ECommonInputType InputType;
UPROPERTY(EditDefaultsOnly, Category = "Gamepad", meta=(EditCondition="InputType == ECommonInputType::Gamepad", GetOptions = GetRegisteredGamepads))
FName GamepadName;
UPROPERTY(EditDefaultsOnly, Category = "Gamepad", meta = (EditCondition = "InputType == ECommonInputType::Gamepad"))
FText GamepadDisplayName;
UPROPERTY(EditDefaultsOnly, Category = "Gamepad", meta=(EditCondition="InputType == ECommonInputType::Gamepad"))
FText GamepadCategory;
UPROPERTY(EditDefaultsOnly, Category = "Gamepad", meta = (EditCondition = "InputType == ECommonInputType::Gamepad"))
FText GamepadPlatformName;
UPROPERTY(EditDefaultsOnly, Category = "Gamepad", meta=(EditCondition="InputType == ECommonInputType::Gamepad"))
TArray<FInputDeviceIdentifierPair> GamepadHardwareIdMapping;
UPROPERTY(EditDefaultsOnly, Category = "Display")
TSoftObjectPtr<UTexture2D> ControllerTexture;
UPROPERTY(EditDefaultsOnly, Category = "Display")
TSoftObjectPtr<UTexture2D> ControllerButtonMaskTexture;
UPROPERTY(EditDefaultsOnly, Category = "Display", Meta = (TitleProperty = "Key"))
TArray<FCommonInputKeyBrushConfiguration> InputBrushDataMap;
UPROPERTY(EditDefaultsOnly, Category = "Display", Meta = (TitleProperty = "Keys"))
TArray<FCommonInputKeySetBrushConfiguration> InputBrushKeySets;
UFUNCTION()
static const TArray<FName>& GetRegisteredGamepads();
private:
#if WITH_EDITOR
virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override;
#endif
};
- InputType
- CommonUI에서 인식하는 Input의 종류
UENUM(BlueprintType)
enum class ECommonInputType : uint8
{
MouseAndKeyboard,
Gamepad,
Touch,
Count
};
- GamepadName
- Controller가 Gamepad인 경우에 해당 Gamepad가 대응 할 Platform
USTRUCT()
struct FInputDeviceIdentifierPair
{
GENERATED_BODY()
UPROPERTY(EditDefaultsOnly, Category = "Gamepad")
FName InputDeviceName;
UPROPERTY(EditDefaultsOnly, Category = "Gamepad")
FString HardwareDeviceIdentifier;
};
- GamepadhardwareIdMapping
- Gamepad Hardware ID를 게임에서 사용하는 Key값과 연결
USTRUCT(Blueprintable)
struct COMMONINPUT_API FCommonInputKeyBrushConfiguration
{
GENERATED_BODY()
public:
FCommonInputKeyBrushConfiguration();
const FSlateBrush& GetInputBrush() const { return KeyBrush; }
public:
UPROPERTY(EditAnywhere, Category = "Key Brush Configuration")
FKey Key;
UPROPERTY(EditAnywhere, Category = "Key Brush Configuration")
FSlateBrush KeyBrush;
};
- InputBrushDataMap
- UI Element 및 Icon에 대한 Key Mapping
USTRUCT(Blueprintable)
struct COMMONINPUT_API FCommonInputKeySetBrushConfiguration
{
GENERATED_BODY()
public:
FCommonInputKeySetBrushConfiguration();
const FSlateBrush& GetInputBrush() const { return KeyBrush; }
public:
UPROPERTY(EditAnywhere, Category = "Key Brush Configuration", Meta = (TitleProperty = "KeyName"))
TArray<FKey> Keys;
UPROPERTY(EditAnywhere, Category = "Key Brush Configuration")
FSlateBrush KeyBrush;
};
- InputBrushKeySets
- 단일 UI Element에 대한 다수의 Key Mapping
- D-Pad 및 기타 여러 Axis에 Mapping 될 가능성이 있는 Input에 유용
Common UI widget
- Common UI Plugin에서 제공하는 Widget
- 기존에 자주 사용하는 Widget의 기능을 거의 그대로 제공
- 다만 Base UMG Widget Style 기능은 제공하지 않는다.
- 대신 Common Style Asset을 참조해 다수의 Menu와 HUD에 일관된 Style을 적용할 수 있다.
- Styple Asset을 변경하면 모든 Common UI Widget에 효과가 나타난다.
- 자세한 지원 Widget 항목에 대해서는 아래 개별 포스트 참고
Common Style Asset
- Create New Blueprint Class를 통해 사진과 같이 Common Style BP를 생성한다.
- 생성한 Common Style BP의 Detail 항목에 필요한 정보를 채워놓는다.
- 생성한 Common Style BP는 이를 필요로 하는 다른 CommonUI에 연결하여 적용한다.
- 위 사진의 경우, Common Button의 Widget Element인 Common Text에 CommonTextStyle을 적용하였다.
- 생성된 Common Style BP는 Project Settings -> Plugins -> Common UI Editor의 Template Styles에 할당할 수 있다.
- 그럼 수동으로 설정되지 않은 Common BP에서 Template Style을 자동으로 사용하게 된다.
- 이와 같은 맥락으로, Project Settings -> Plugins -> Common UI Framework에서
몇 가지 Global Assset을 추가로 지원한다.- Loading 화면에서 쓰는 Default Throbber Material
- Load되지 않은 UI Asset에 표시되는 Default Image Resource Object 등
Technical Guide
- Designer나 Artist는 크게 신경 안 써도 되지만 Tech는 알아둬야 할 코드 영역 내용
- https://redchiken.tistory.com/395
FAQ
- Design이나 구조적으로 자주 나오는 질문에 대한 모음
- https://redchiken.tistory.com/396
'UE5 > UI' 카테고리의 다른 글
[UI] Common UI FAQ (0) | 2024.07.10 |
---|---|
[UI] CommonUI Technical Guide (0) | 2024.07.10 |
[UI] Common UI Widget (0) | 2024.07.10 |
[UI] UMG ViewModel (0) | 2024.07.08 |
[UI] Optimization (0) | 2024.07.01 |