--- 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> Layers;`进行多UI层的管理,不同Layer使用GameplayTag进行区分。Lyra的UILayer分为以下4个层: - UI.Layer.Game - UI.Layer.GameMenu - UI.Layer.Menu - UI.Layer.Modal ```c++ template TSharedPtr PushWidgetToLayerStackAsync(FGameplayTag LayerName, bool bSuspendInputUntilComplete, TSoftClassPtr ActivatableWidgetClass, TFunction StateFunc) { static_assert(TIsDerivedFrom::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 StreamingHandle = StreamableManager.RequestAsyncLoad(ActivatableWidgetClass.ToSoftObjectPath(), FStreamableDelegate::CreateWeakLambda(this, [this, LayerName, ActivatableWidgetClass, StateFunc, SuspendInputToken]() { UCommonUIExtensions::ResumeInputForPlayer(GetOwningPlayer(), SuspendInputToken); ActivatableWidgetT* Widget = PushWidgetToLayerStack(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 ActivatableWidgetT* PushWidgetToLayerStack(FGameplayTag LayerName, UClass* ActivatableWidgetClass) { return PushWidgetToLayerStack(LayerName, ActivatableWidgetClass, [](ActivatableWidgetT&) {}); } template ActivatableWidgetT* PushWidgetToLayerStack(FGameplayTag LayerName, UClass* ActivatableWidgetClass, TFunctionRef InitInstanceFunc) { static_assert(TIsDerivedFrom::IsDerived, "Only CommonActivatableWidgets can be used here"); if (UCommonActivatableWidgetContainerBase* Layer = GetLayerWidget(LayerName)) { return Layer->AddWidget(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 WeakThis = this; StreamingHandle = RootLayout->PushWidgetToLayerStackAsync(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(); } } ```