BlueRoseNote/03-UnrealEngine/Gameplay/Lyra/UE5 Lyra学习笔记(6)—CommonUI.md

135 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: UE5 Lyra学习笔记(6)—CommonUI
date: 2024-03-22 15:03:59
excerpt:
tags:
rating: ⭐
---
# 前言
- 全局管理类
- UGameUIManagerSubsystem父类为UGameInstanceSubsystem主要的功能是管理CurrentPolicy(UGameUIPolicy)。
- UGameUIPolicy将UPrimaryGameLayout添加到Viewport中。
- UPrimaryGameLayout
- Widgets
使用[[#GameplayAbility]]检测玩家输入并且开启UI。
# UPrimaryGameLayout
父类为UCommonUserWidget。主要功能为UILayer以及Dormant状态管理。
## UILayer
使用`TMap<FGameplayTag, TObjectPtr<UCommonActivatableWidgetContainerBase>> Layers;`进行多UI层的管理不同Layer使用GameplayTag进行区分。Lyra的UILayer分为以下4个层
- UI.Layer.Game
- UI.Layer.GameMenu
- UI.Layer.Menu
- UI.Layer.Modal
```c++
template <typename ActivatableWidgetT = UCommonActivatableWidget>
TSharedPtr<FStreamableHandle> PushWidgetToLayerStackAsync(FGameplayTag LayerName, bool bSuspendInputUntilComplete, TSoftClassPtr<UCommonActivatableWidget> ActivatableWidgetClass, TFunction<void(EAsyncWidgetLayerState, ActivatableWidgetT*)> StateFunc)
{
static_assert(TIsDerivedFrom<ActivatableWidgetT, UCommonActivatableWidget>::IsDerived, "Only CommonActivatableWidgets can be used here");
static FName NAME_PushingWidgetToLayer("PushingWidgetToLayer");
const FName SuspendInputToken = bSuspendInputUntilComplete ? UCommonUIExtensions::SuspendInputForPlayer(GetOwningPlayer(), NAME_PushingWidgetToLayer) : NAME_None;
FStreamableManager& StreamableManager = UAssetManager::Get().GetStreamableManager();
TSharedPtr<FStreamableHandle> StreamingHandle = StreamableManager.RequestAsyncLoad(ActivatableWidgetClass.ToSoftObjectPath(), FStreamableDelegate::CreateWeakLambda(this,
[this, LayerName, ActivatableWidgetClass, StateFunc, SuspendInputToken]()
{
UCommonUIExtensions::ResumeInputForPlayer(GetOwningPlayer(), SuspendInputToken);
ActivatableWidgetT* Widget = PushWidgetToLayerStack<ActivatableWidgetT>(LayerName, ActivatableWidgetClass.Get(), [StateFunc](ActivatableWidgetT& WidgetToInit) {
StateFunc(EAsyncWidgetLayerState::Initialize, &WidgetToInit);
});
StateFunc(EAsyncWidgetLayerState::AfterPush, Widget);
})
);
// Setup a cancel delegate so that we can resume input if this handler is canceled.
StreamingHandle->BindCancelDelegate(FStreamableDelegate::CreateWeakLambda(this,
[this, StateFunc, SuspendInputToken]()
{
UCommonUIExtensions::ResumeInputForPlayer(GetOwningPlayer(), SuspendInputToken);
StateFunc(EAsyncWidgetLayerState::Canceled, nullptr);
})
);
return StreamingHandle;
}
template <typename ActivatableWidgetT = UCommonActivatableWidget>
ActivatableWidgetT* PushWidgetToLayerStack(FGameplayTag LayerName, UClass* ActivatableWidgetClass)
{
return PushWidgetToLayerStack<ActivatableWidgetT>(LayerName, ActivatableWidgetClass, [](ActivatableWidgetT&) {});
}
template <typename ActivatableWidgetT = UCommonActivatableWidget>
ActivatableWidgetT* PushWidgetToLayerStack(FGameplayTag LayerName, UClass* ActivatableWidgetClass, TFunctionRef<void(ActivatableWidgetT&)> InitInstanceFunc)
{
static_assert(TIsDerivedFrom<ActivatableWidgetT, UCommonActivatableWidget>::IsDerived, "Only CommonActivatableWidgets can be used here");
if (UCommonActivatableWidgetContainerBase* Layer = GetLayerWidget(LayerName))
{
return Layer->AddWidget<ActivatableWidgetT>(ActivatableWidgetClass, InitInstanceFunc);
}
return nullptr;
}
```
### RegisterLayer
用于向PrimaryGameLayout注册UILayer。为了方便管理里面的CommonActivatabbleWidgetStack)
```c++
void RegisterLayer(UPARAM(meta = (Categories = "UI.Layer")) FGameplayTag LayerTag, UCommonActivatableWidgetContainerBase* LayerWidget);
```
Content/UI的W_OverallUILayout调用它是一个根组件为Overlay下面有4个子组件(CommonActivatabbleWidgetStack)
- GameLayer_Stack游戏内UI类似HUD。
- GameMenu_Stack游戏相关的 "菜单",例如游戏中的库存用户界面。
- Menu_Stack设置界面等。
- Model_Stack游戏内的模态确认对话框、错误对话框。
# GameplayAbility
Lyra使用2个位于Plugins/ShooterCore/Content/Input/Abilites/
- GAB_ShowWidget_WhenInputPressed
- GAB_ShowWidget_WhileInputHeld
GAB_ShowWidget_WhenInputPressed![[GAB_ShowWidget_WhenInputPressed.png|800]]
GAB_ShowWidget_WhileInputHeld略微复杂一些会多一些![[GAB_ShowWidget_WhileInputHeld.png|1200]]
## GameplayTasks
- UCancellableAsyncAction
- [[#UAsyncAction_PushContentToLayerForPlayer]]
核心函数逻辑如下主要调用UPrimaryGameLayout::PushWidgetToLayerStackAsync()
```c++
void UAsyncAction_PushContentToLayerForPlayer::Activate()
{
if (UPrimaryGameLayout* RootLayout = UPrimaryGameLayout::GetPrimaryGameLayout(OwningPlayerPtr.Get()))
{
TWeakObjectPtr<UAsyncAction_PushContentToLayerForPlayer> WeakThis = this;
StreamingHandle = RootLayout->PushWidgetToLayerStackAsync<UCommonActivatableWidget>(LayerName, bSuspendInputUntilComplete, WidgetClass, [this, WeakThis](EAsyncWidgetLayerState State, UCommonActivatableWidget* Widget) {
if (WeakThis.IsValid())
{
switch (State)
{
case EAsyncWidgetLayerState::Initialize:
BeforePush.Broadcast(Widget);
break;
case EAsyncWidgetLayerState::AfterPush:
AfterPush.Broadcast(Widget);
SetReadyToDestroy();
break;
case EAsyncWidgetLayerState::Canceled:
SetReadyToDestroy();
break;
}
}
SetReadyToDestroy();
});
}
else
{
SetReadyToDestroy();
}
}
```