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

135 lines
5.4 KiB
Markdown
Raw Permalink Normal View History

2024-03-22 16:45:37 +08:00
---
title: UE5 Lyra学习笔记(6)—CommonUI
date: 2024-03-22 15:03:59
excerpt:
tags:
rating: ⭐
---
# 前言
- 全局管理类
2024-03-22 19:08:41 +08:00
- UGameUIManagerSubsystem父类为UGameInstanceSubsystem主要的功能是管理CurrentPolicy(UGameUIPolicy)。
- UGameUIPolicy将UPrimaryGameLayout添加到Viewport中。
2024-03-22 16:45:37 +08:00
- UPrimaryGameLayout
- Widgets
使用[[#GameplayAbility]]检测玩家输入并且开启UI。
2024-03-22 19:08:41 +08:00
# 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
2024-03-22 16:45:37 +08:00
2024-03-22 19:08:41 +08:00
```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");
2024-03-22 16:45:37 +08:00
2024-03-22 19:08:41 +08:00
static FName NAME_PushingWidgetToLayer("PushingWidgetToLayer");
const FName SuspendInputToken = bSuspendInputUntilComplete ? UCommonUIExtensions::SuspendInputForPlayer(GetOwningPlayer(), NAME_PushingWidgetToLayer) : NAME_None;
2024-03-22 16:45:37 +08:00
2024-03-22 19:08:41 +08:00
FStreamableManager& StreamableManager = UAssetManager::Get().GetStreamableManager();
TSharedPtr<FStreamableHandle> StreamingHandle = StreamableManager.RequestAsyncLoad(ActivatableWidgetClass.ToSoftObjectPath(), FStreamableDelegate::CreateWeakLambda(this,
[this, LayerName, ActivatableWidgetClass, StateFunc, SuspendInputToken]()
{
UCommonUIExtensions::ResumeInputForPlayer(GetOwningPlayer(), SuspendInputToken);
2024-03-22 16:45:37 +08:00
2024-03-22 19:08:41 +08:00
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游戏内的模态确认对话框、错误对话框。
2024-03-22 16:45:37 +08:00
# 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();
}
}
```