4.8 KiB
UItemTracer
基本信息
- 类型: UCLASS(BlueprintType)
- 父类: UObject
- 源文件: Plugins/Item/Source/Item/Public/ItemFactory.h
- 模块: Item
功能概述
嵌入在FItemInstance属性包中的轻量级追踪对象。存储当前容器位置,并暴露OnItemMoved多播委托。提供Blueprint查询函数用于查询物品位置。
设计用意
解决"物品在哪"的问题,无需全局注册表。存在于物品的属性包中(随物品迁移)。由IItemContainer::InjectPayload NVI包装自动更新。OnItemMoved委托使UI/任务系统能响应物品移动事件。
职责范围
追踪和广播物品位置变化。由InjectPayload在插入时更新位置。UPROPERTY位置使用TObjectPtr(非强引用),避免泄漏。
项目内依赖
(无项目内依赖)
对外接口
UItemTracer 是 BlueprintType,嵌入在物品的属性包中(键名为 Internal_ItemTracer),随物品在容器间迁移。外部代码通过属性包获取 Tracer 引用后,可调用以下接口:
Blueprint 可调用:
- GetItemLocation() (BlueprintPure, BlueprintAuthorityOnly) → const UObject*: 返回物品当前所在的 UObject 位置。在 InjectPayload NVI 中,此位置被设置为容器对象(Cast(this))。返回值可能为空(物品尚未被注入任何容器)。
- FindActorInOuterChain() (BlueprintPure, BlueprintAuthorityOnly) → const AActor*: 从物品位置出发,沿 Outer 链向上查找第一个 AActor。如果物品容器是 Actor 的组件/子对象,此方法可追溯到所属 Actor。找不到则返回 nullptr。
委托:
- OnItemMoved (FOnItemMoved, BlueprintAssignable): DYNAMIC_MULTICAST_DELEGATE_OneParam 类型的动态多播委托。在 IItemContainer::InjectPayload 中被广播(参数为 Tracer 自身)。UI 或任务系统可绑定此委托以响应物品移动事件。
C++ 专用:
- SetItemLocation(UObject)*: 设置 Tracer 的位置引用。不暴露到 Blueprint。仅由 IItemContainer::InjectPayload NVI 调用(ItemContainer.cpp:59),确保位置更新与移动广播的原子性。
使用方法
UItemTracer 由 ItemFactory 创建并嵌入物品属性包,由 InjectPayload 自动更新。外部代码(如 Blueprint UI)从物品属性包中获取 Tracer 引用后使用。
创建(ItemFactory.cpp:17-22):
if (ItemDef.bHasTracer)
{
Instance->ItemData.AddProperty(UInternalItemProperty::ItemTracer(),
EPropertyBagPropertyType::Object, UItemTracer::StaticClass());
UItemTracer* NewTracer = NewObject<UItemTracer>();
Instance->ItemData.SetValueObject(
UInternalItemProperty::ItemTracer(), NewTracer);
}
位置更新(ItemContainer.cpp:45-67 - InjectPayload NVI):
void IItemContainer::InjectPayload(TUniquePtr<struct FItemInstance> Payload)
{
if (!Payload.IsValid()) return;
const FName PropName = UInternalItemProperty::ItemTracer();
if (const FPropertyBagPropertyDesc* Desc =
Payload->ItemData.FindPropertyDescByName(PropName))
{
if (UObject* SelfAsObject = Cast<UObject>(this))
{
TValueOrError<UObject*, EPropertyBagResult> Result =
Payload->ItemData.GetValueObject(PropName);
if (Result.HasValue())
{
if (UItemTracer* Tracer = Cast<UItemTracer>(Result.GetValue()))
{
Tracer->SetItemLocation(SelfAsObject);
Tracer->OnItemMoved.Broadcast(Tracer); // 广播移动事件
}
}
}
}
InjectPayloadImpl(MoveTemp(Payload));
}
在 Blueprint 中绑定移动事件: UI 或任务系统通过获取物品属性包中的 Internal_ItemTracer 对象,绑定其 OnItemMoved 委托来响应物品移动。当容器调用 InjectPayload 时,委托被广播,绑定的监听方收到通知。
查询位置: 在 Blueprint 中调用 GetItemLocation 获取物品当前所在 UObject,或调用 FindActorInOuterChain 追溯到所属 Actor。
用例
Plugins/Item/Source/Item/Public/ItemFactory.h:27-- FOnItemMoved 委托类型声明(DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam)。Plugins/Item/Source/Item/Public/ItemFactory.h:29-57-- UItemTracer 类定义(OnItemMoved 成员 + GetItemLocation / FindActorInOuterChain / SetItemLocation 方法)。Plugins/Item/Source/Item/Private/ItemFactory.cpp:17-22-- CreateItemInstance 中当 bHasTracer 为 true 时创建 UItemTracer 并添加到属性包。Plugins/Item/Source/Item/Private/ItemContainer.cpp:49-- InjectPayload NVI 中通过 UInternalItemProperty::ItemTracer() 键名查找 Tracer。Plugins/Item/Source/Item/Private/ItemContainer.cpp:57-60-- InjectPayload 中 Cast 到 UItemTracer,调用 SetItemLocation 更新位置,Broadcast OnItemMoved 通知监听方。