动态属性系统

The documentation of Generic Game Framework.

通用库存系统.封面
罗传月武(YueWu)

作者

罗传月武(YueWu)

专注游戏开发和Web技术。

创建时间: 2025年6月24日更新时间: 2026年9月15日

目录

介绍

灵感来自于Lyra的GampelayTagStack,是通过GameplayTag->Integer来追踪管理动态数值的一种机制。在GIS中,进一步扩大了这个概念,并将其称为Tag属性容器。

仅供C++用户

本文仅针对希望利用该系统开发其它游戏系统的C++用户,蓝图用户不需要阅读此文章。

Tag属性容器

GIS封装了2种方式以实现动态属性系统,分别是:

  • GameplayTagIntegerContainer:包含一个GameplayTagInteger列表,每一项表示一个Tag到Int32的键值对。
  • GameplayTagFloatContianer:包含一个GameplayTagFloat列表,每一项表示一个Tag到float的键值对。

它们均由FastArraySerializer实现,提供高效的网络复制,和简化的数据变化通知回调,Container中的每一项,也都标记了SaveGame,便于在单机游戏,或者服务端进行数据序列化。

使用属性容器步骤

以道具实例为例,添加Container到你的类中。

cpp
1 /**
2 * Container for integer attributes of the item instance.
3 * 道具实例的整数属性容器。
4 */
5 UPROPERTY(VisibleAnywhere, Replicated, Category="ItemInstance", SaveGame, meta=(DisplayName="Attributes (Integer)", ShowOnlyInnerProperties))
6 FGIS_GameplayTagIntegerContainer IntegerAttributes;
7
8 /**
9 * Container for float attributes of the item instance.
10 * 道具实例的浮点属性容器。
11 */
12 UPROPERTY(VisibleAnywhere, Replicated, Category="ItemInstance", SaveGame, meta=(DisplayName="Attributes (Float)", ShowOnlyInnerProperties))
13 FGIS_GameplayTagFloatContainer FloatAttributes;

在构造函数中,将当前对象设置到容器的ContainerOwner。(如果你是使用的ActorComponent,请在InitializeComponent中设置Owner)

cpp
1UGIS_ItemInstance::UGIS_ItemInstance(const FObjectInitializer& ObjectInitializer): Super(ObjectInitializer), IntegerAttributes(this), FloatAttributes(this)

确保该字段正确网络同步,同步条件可以根据项目需求自定义。

cpp
1void UGIS_ItemInstance::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
2{
3 Super::GetLifetimeReplicatedProps(OutLifetimeProps);
4
5
6 // FastArray don't need push model.
7 DOREPLIFETIME(ThisClass, IntegerAttributes);
8 DOREPLIFETIME(ThisClass, FloatAttributes);
9}
10

确保你的Class同时实现了IGIS_GameplayTagIntegerContainerOwnerIGIS_GameplayTagFloatContainerOwner接口

cpp
1class GENERICINVENTORYSYSTEM_API UGIS_ItemInstance : public UObject, public IGameplayTagAssetInterface, public IGIS_MixinOwnerInterface, public IGIS_GameplayTagFloatContainerOwner,
2 public IGIS_GameplayTagIntegerContainerOwner

然后实现接口中的OnTagFloatUpdateOnTagIntegerUpdate,该接口允许你针对属性变化做出反应。

cpp
1 /**
2 * Called when a float attribute is updated.
3 * 浮点型属性更新时调用。
4 * @param Tag The gameplay tag identifying the attribute. 标识属性的游戏标签。
5 * @param OldValue The previous value of the attribute. 属性之前的值。
6 * @param NewValue The new value of the attribute. 属性的新值。
7 */
8 virtual void OnTagFloatUpdate(const FGameplayTag& Tag, float OldValue, float NewValue) override final;
9
10 /**
11 * Called when an integer attribute is updated.
12 * 整型属性更新时调用。
13 * @param Tag The gameplay tag identifying the attribute. 标识属性的游戏标签。
14 * @param OldValue The previous value of the attribute. 属性之前的值。
15 * @param NewValue The new value of the attribute. 属性的新值。
16 */
17 virtual void OnTagIntegerUpdate(const FGameplayTag& Tag, int32 OldValue, int32 NewValue) override final;

OnTagFloatUpdateOnTagIntegerUpdate会在任意属性变更时调用,包括服务端和客户端。

应用案例

此特性是为了让动态属性变得更容易实现,代码是可复用的。

道具实例到了动态属性。当然,你也可以将其应用到其他系统中,而不仅仅只是库存系统。