134 lines
5.3 KiB
Markdown
134 lines
5.3 KiB
Markdown
|
---
|
|||
|
title: UE5 Lyra学习笔记(5)—QuickBar与Equipment
|
|||
|
date: 2022-09-16 11:03:03
|
|||
|
excerpt:
|
|||
|
tags:
|
|||
|
rating: ⭐
|
|||
|
---
|
|||
|
## 前言
|
|||
|
|
|||
|
|
|||
|
## ULyraQuickBarComponent
|
|||
|
继承自UControllerComponent(ModularGame的给Controller使用的胶水组件)。
|
|||
|
|
|||
|
### 成员变量
|
|||
|
```c++
|
|||
|
//QuickBar Slot中的ItemInstance数据
|
|||
|
UPROPERTY(ReplicatedUsing=OnRep_Slots)
|
|||
|
TArray<TObjectPtr<ULyraInventoryItemInstance>> Slots;
|
|||
|
|
|||
|
//当前激活的SlotIndex
|
|||
|
UPROPERTY(ReplicatedUsing=OnRep_ActiveSlotIndex)
|
|||
|
int32 ActiveSlotIndex = -1;
|
|||
|
|
|||
|
//当前装备的EquipmentInstance
|
|||
|
UPROPERTY()
|
|||
|
TObjectPtr<ULyraEquipmentInstance> EquippedItem;
|
|||
|
```
|
|||
|
2个OnRep()会使用GameplayMessageRouter发送Message,该Message最后会被UI接收并且进行对应处理。
|
|||
|
|
|||
|
### 函数
|
|||
|
只说几个相对重要的函数:
|
|||
|
- CycleActiveSlotForward:激活正向的下一个QuickBarSlot,判断Index是否有效后调用SetActiveSlotIndex()。
|
|||
|
- CycleActiveSlotBackward:激活反向的上一个QuickBarSlot,判断Index是否有效后调用SetActiveSlotIndex()。
|
|||
|
- EquipItemInSlot:装备指定的物品,通过`Slot[ActiveSlotIndex]`获取到ItemInstance,ItemInstance通过Fragment获取到EquipmentDefinition后用EquipmentManager调用函数EquipItem()来装备(调用FindEquipmentManager获取)。
|
|||
|
- UnequipItemInSlot:脱下指定的物品,EquipmentManager调用UnequipItem(EquippedItem)。
|
|||
|
- FindEquipmentManager:`Cast<AController>(GetOwner()))->GetPawn()->FindComponentByClass<ULyraEquipmentManagerComponent>()`
|
|||
|
- SetActiveSlotIndex_Implementation:含有`Server, Reliable`标记,依次调用`UnequipItemInSlot(); ActiveSlotIndex = NewIndex; EquipItemInSlot(); OnRep_ActiveSlotIndex(); `
|
|||
|
- AddItemToSlot:增加QuickBarSlot的ItemInstance数据并调用OnRep_Slots()。
|
|||
|
- RemoveItemFromSlot:如果处于装备状态会先调用UnequipItemInSlot(),之后移除QuickBarSlot的ItemInstance数据并调用OnRep_Slots()。
|
|||
|
|
|||
|
### QuickBarUI
|
|||
|
- W_QuickBar(组合控件):快捷栏主控件,用于嵌套W_QuickBarSlot。
|
|||
|
- W_QuickBarSlot:
|
|||
|
1. 通过GameplayMessageRouter读取FLyraQuickBarActiveIndexChangedMessage数据(QuickBar组件的消息),获取Payload拥有者是否与UI拥有者相同,来播放对应的UI动画。
|
|||
|
2. 通过GameplayMessageRouter读取FLyraQuickBarSlotsChangedMessage数据(QuickBar组件的消息),获取Payload拥有者以及ItemInstance数据,通过ItemInstance找到到指定的Fragment来获取图标资源来更新UI的图标。
|
|||
|
- W_WeaponAmmoAndName:取得角色的QuickBar组件,之后获取ActiveSlot的ItemInstance,获取对应的StatTag来设置显示Text(MagazineAmmo、SpareAmmo),再通过Fragment找到对应的图标资产。
|
|||
|
- 其他控件:
|
|||
|
- W_ActionTouchButton:通过GameplayMessageRouter读取消息,获得Duration值。
|
|||
|
|
|||
|
## ULyraEquipmentManagerComponent
|
|||
|
继承自UPawnComponent。(ModularGame的给Pawn使用的胶水组件)。
|
|||
|
|
|||
|
### 成员变量
|
|||
|
|
|||
|
### 相关逻辑
|
|||
|
- UI
|
|||
|
- 获取角色对应组件逻辑:`GetOwningPlayer->GetComponentByClass<ULyraQuickBarComponent>();`
|
|||
|
- C++
|
|||
|
- Controll组件获取到角色组件方法:`Cast<AController>(GetOwner()))->GetPawn()->FindComponentByClass<ULyraEquipmentManagerComponent>()`
|
|||
|
|
|||
|
### ItemInstance获取Pawn的方法
|
|||
|
```c++
|
|||
|
void ULyraEquipmentInstance::OnUnequipped()
|
|||
|
{
|
|||
|
K2_OnUnequipped();
|
|||
|
}
|
|||
|
|
|||
|
APawn* ULyraEquipmentInstance::GetPawn() const
|
|||
|
{
|
|||
|
return Cast<APawn>(GetOuter());
|
|||
|
}
|
|||
|
|
|||
|
APawn* ULyraEquipmentInstance::GetTypedPawn(TSubclassOf<APawn> PawnType) const
|
|||
|
{
|
|||
|
APawn* Result = nullptr;
|
|||
|
if (UClass* ActualPawnType = PawnType)
|
|||
|
{
|
|||
|
if (GetOuter()->IsA(ActualPawnType))
|
|||
|
{
|
|||
|
Result = Cast<APawn>(GetOuter());
|
|||
|
}
|
|||
|
}
|
|||
|
return Result;
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
## UI从ItemDefinition获取数据的方式
|
|||
|
调用ItemInstance->FindFragmentByClass,再从指定的FragmentClass中获取数据。
|
|||
|
QuickBar使用了QuickBarIcon
|
|||
|
|
|||
|
```c++
|
|||
|
void ULyraQuickBarComponent::EquipItemInSlot()
|
|||
|
|
|||
|
{
|
|||
|
check(Slots.IsValidIndex(ActiveSlotIndex));
|
|||
|
check(EquippedItem == nullptr);
|
|||
|
if (ULyraInventoryItemInstance* SlotItem = Slots[ActiveSlotIndex])
|
|||
|
{
|
|||
|
if (const UInventoryFragment_EquippableItem* EquipInfo = SlotItem->FindFragmentByClass<UInventoryFragment_EquippableItem>())
|
|||
|
{
|
|||
|
TSubclassOf<ULyraEquipmentDefinition> EquipDef = EquipInfo->EquipmentDefinition;
|
|||
|
if (EquipDef != nullptr)
|
|||
|
{
|
|||
|
if (ULyraEquipmentManagerComponent* EquipmentManager = FindEquipmentManager())
|
|||
|
{
|
|||
|
EquippedItem = EquipmentManager->EquipItem(EquipDef);
|
|||
|
if (EquippedItem != nullptr)
|
|||
|
{
|
|||
|
EquippedItem->SetInstigator(SlotItem);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
### QuickBar UI更新机制
|
|||
|
Lyra选择 tick来 getSlot
|
|||
|
```c++
|
|||
|
TArray<ULyraInventoryItemInstance*> GetSlots() const
|
|||
|
{
|
|||
|
return Slots;
|
|||
|
}
|
|||
|
|
|||
|
UPROPERTY(ReplicatedUsing=OnRep_Slots)
|
|||
|
TArray<TObjectPtr<ULyraInventoryItemInstance>> Slots;
|
|||
|
```
|
|||
|
|
|||
|
之后根据Slot进行设置图标数据或者将其设置成null。
|
|||
|
|
|||
|
PS.所以我打算这么做:ItemUISlot设置成null,之后遍历消除nullslot
|