【UE5 C++课程系列笔记】12——Gameplay标签的基本使用

目录

概念

主要作用

1 组织与分类游戏元素

1.1 驱动游戏逻辑

1.2 便于查询与筛选

2 助力网络同步与优化

定义Gameplay标签

1 在项目设置中添加标签 

2 从数据表资产导入标签

3 使用C++定义标签

3.1 UE_DECLARE_GAMEPLAY_TAG_EXTERN

3.2 UE_DEFINE_GAMEPLAY_TAG

3.3 UE_DEFINE_GAMEPLAY_TAG_COMMENT

3.4 UE_DEFINE_GAMEPLAY_TAG_STATIC

*3.5 完整步骤

使用Gameplay标签

1 将标签应用于对象

2 使用条件函数对标签求值

3 Gameplay标记查询

4 在C++中使用Gameplay标签

5 通过IGameplayTagAssetInterface访问Gameplay标签


概念

        Gameplay标签(分层标签系统) 是用户定义的字符串,充当概念性的分层标签。你可以将Gameplay标签应用于项目中的对象,并对其求值以驱动你的Gameplay实现,类似于检查布尔值或标记。Gameplay标签本质上是一种有层级结构的文本标识,通常以 “.” 作为层级分隔符,形如 “Category.Subcategory.Item”,这样的结构方便进行分类管理以及灵活的查询和匹配操作。

主要作用

1 组织与分类游戏元素

        游戏中存在大量不同种类的对象、状态、行为等,比如角色的各种技能(攻击技能、防御技能、辅助技能等)、不同类型的道具(武器、防具、消耗品等)、场景中的各种交互元素(可破坏物、可触发机关等)。通过为它们赋予相应的 Gameplay 标签,可以清晰地将这些元素按照不同的逻辑范畴进行归类。例如,可以给所有治疗技能贴上 “Skill.Healing” 标签,给近战武器贴上 “Item.Weapon.Melee” 标签,方便开发人员从整体上把握游戏内容的构成。

1.1 驱动游戏逻辑

        条件判断依据:在编写游戏逻辑时,常常需要根据不同的条件来决定是否执行某些操作。Gameplay 标签就可以作为很好的判断条件。例如,在一个角色扮演游戏中,技能释放逻辑可能会检查角色是否具有 “Status.Buff.Strength”(力量增益状态)标签,若有,则某个特定的强力攻击技能可以被释放;或者检查目标是否带有 “Status.Debuff.Vulnerable”(易伤状态)标签,来决定伤害计算的系数等。

        触发事件响应:可以基于 Gameplay 标签的添加、移除等变化来触发相应的事件。比如当角色进入 “State.Invisible”(隐身状态)这个标签所代表的状态时,游戏中的敌人 AI 可以监听该标签变化事件,进而调整搜索策略或者进入警戒状态等,实现不同游戏系统之间的协同和交互。

1.2 便于查询与筛选

        精确查找:开发人员可以根据具体的标签精确地找到特定的游戏元素。比如在一个复杂的道具系统中,要找到所有带有 “Item.Consumable.HealthPotion”(消耗品 - 生命药水)标签的道具,以便进行批量处理,如更新其属性、调整其在商店中的售价等。

        模糊筛选:凭借标签的层级结构,还能进行模糊筛选。假设想获取所有属于 “Item.Weapon”(武器类物品)的元素,无论它是近战、远程还是其他细分类型的武器,都可以通过查找以该父标签开头的所有标签对应的元素来实现,这种方式极大地增强了对游戏内容管理和操作的灵活性。

2 助力网络同步与优化

        在网络游戏中,为了减少不必要的数据传输量、节省网络带宽以及降低服务器和客户端的运算负载,Gameplay 标签发挥着重要作用。可以规定只有带有特定关键 Gameplay 标签的游戏数据才需要在网络间进行同步。例如,对于场景中那些带有 “Object.NetworkSync”(网络同步对象)标签的物体,才会将其位置、状态等关键信息发送给客户端,而其他无关紧要的物体信息则无需同步,以此提高网络传输的效率。

定义Gameplay标签

1 在项目设置中添加标签 

在“项目设置-》GameplayTags”中点击“新增Gameplay标签源”

这里命名为“Test.ini”

点击“管理Gameplay标签”

在打开的“Gameplay标签管理器”界面中点击加号来新增Gameplay标签

编辑标签的命名、注释如下,设置源为刚创建的“Test.ini”

编辑好后点击“添加新标签”

添加好后可以在项目目录中找到“Test.ini” 

打开后内容如下

在“Gameplay标签管理器”中可以对Gameplay标签进行添加子标签、重命名、删除等操作。

2 从数据表资产导入标签

添加一个数据表格 

行结构选择“GameplayTagTableRow”

这里命名为“DT_TableTag”

打开“DT_TableTag”,这里添加3行数据

对这3行数据的标签和注释进行编辑 

在“项目设置-》GameplayTags”中,点击添加一个Gameplay标签列表元素

这里设置为刚创建的“DT_TableTag”

此时再次打开“Gameplay标签管理器”

可以看到“Gameplay标签管理器”界面中出现了在“DT_TableTag”中编辑的标签

3 使用C++定义标签

可以使用宏“UE_DECLARE_GAMEPLAY_TAG_EXTERN”、“UE_DEFINE_GAMEPLAY_TAG”、“UE_DEFINE_GAMEPLAY_TAG_COMMENT”、“UE_DEFINE_GAMEPLAY_TAG_STATIC”来定义Gameplay标签。        

3.1 UE_DECLARE_GAMEPLAY_TAG_EXTERN

        宏“UE_DECLARE_GAMEPLAY_TAG_EXTERN”用于在头文件中声明一个外部的 Gameplay 标签变量,通常在你想要在多个源文件中使用同一个 Gameplay 标签定义时使用。它只是声明了这个标签的存在,具体的定义会在其他源文件中通过对应的 UE_DEFINE_GAMEPLAY_TAG 等宏来完成,用法如下:

// 例如,在某个头文件(比如 MyTags.h)中声明一个外部的 Gameplay 标签
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TagName)  //TagName 是要声明的 Gameplay 标签的名称

3.2 UE_DEFINE_GAMEPLAY_TAG

        用于定义一个 Gameplay 标签,将其注册到虚幻引擎的 Gameplay 标签系统中,使其能够在游戏中被识别和使用。它通常与 UE_DECLARE_GAMEPLAY_TAG_EXTERN 配合使用,先在头文件中声明,再在源文件中定义,不过也可以单独使用来直接定义一个标签,用法如下:

// 在对应的源文件(比如 MyTags.cpp)中定义之前声明的 Gameplay 标签
UE_DEFINE_GAMEPLAY_TAG(TagName, "My.Gameplay.Tag")

3.3 UE_DEFINE_GAMEPLAY_TAG_COMMENT

        该宏除了可定义 Gameplay 标签外,还允许为该标签添加注释说明。这个注释可以帮助其他开发人员更好地理解这个标签所代表的含义、用途等信息,对于代码的可读性和维护性很有帮助,尤其是在项目中有大量 Gameplay 标签存在的情况下,用法如下:

UE_DEFINE_GAMEPLAY_TAG_COMMENT(TagName, "My.Gameplay.Tag", "This is a comment explaining the tag's purpose.")

3.4 UE_DEFINE_GAMEPLAY_TAG_STATIC

        该宏用于静态地定义一个 Gameplay 标签,它与 UE_DEFINE_GAMEPLAY_TAG 的主要区别在于其定义的标签具有静态存储特性,适用于一些特定的场景,比如当你希望这个标签只在某个特定的编译单元内有效,或者不想让它参与到一些动态的 Gameplay 标签管理过程中(例如避免被某些全局的标签查找、修改机制影响等),用法如下:

UE_DEFINE_GAMEPLAY_TAG_STATIC(TagName, "My.Gameplay.Tag")

*3.5 完整步骤

        首先必须将 GameplayTags 模块添加到项目的 Build.cs 文件,才能在C++中访问Gameplay标签功能,如下所示:

新建一个C++类,这里命名为“TagType”,用于定义所有的Gamelay标签

 再新建一个Actor类,这里命名为“TagActor”,用于使用Gamelay标签

在“TagType.h”中使用 NativeGameplayTags.h

继续声明Gameplay标签变量

在“TagType.cpp”中定义Gameplay 标签

在“TagActor.h”中导入“TagType.h”,注意要写在“#include "TagActor.generated.h"”之前

然后我们在“TagActor.cpp”中使用UE_DEFINE_GAMEPLAY_TAG_STATIC宏 定义一个 Gameplay 标签,如下:

编译后,在“Gameplay标签管理器”中可以看到添加的Gameplay标签如下:

使用Gameplay标签

1 将标签应用于对象

2 使用条件函数对标签求值

在“Gameplay标签管理器”中先添加新标签

 接下来去使用Gameplay标签,这里通过关卡蓝图来测试使用。打开关卡蓝图,添加一个变量,这里命名为“TestTagContainer”

变量类型为“Gameplay标签容器”

首先通过“Has Tag”节点来判断“TestTagContainer”是否含有“Test.Two”标签,勾选“Exact Match”表示精确匹配。

判断 “TestTagContainer”是否同时含有“Test.One”和“Test.Three”标签

两个条件必需同时为false结果才是true

“Test.One”和“Test.Three”标签是否存在任意一个。只有当不存在“Test.Two”标签,不同时存在“Test.One”和“Test.Three”标签,并且“Test.One”和“Test.Three”标签至少存在一个的情况下,最终结果才为true。

设置 “TestTagContainer”默认值

运行测试,打印结果为true

3 Gameplay标记查询

        Gameplay 标记查询主要通过FGameplayTagQuery来实现,FGameplayTagQuery是一种逻辑查询,用于针对FGameplayTagContainer进行查询操作,查询成功则称 “匹配”。查询是逻辑表达式,可测试标签容器的交集属性或子表达式的匹配状态,具有递归性和表达性。

        接下来使用“Gameplay标记查询”的方式实现:只有当不存在“Test.Two”标签,不同时存在“Test.One”和“Test.Three”标签,并且“Test.One”和“Test.Three”标签至少存在一个的情况下,最终结果才为true的逻辑。

        首先添加“Does Container Match Tag Query” 节点来判断标签容器是否与标签查询匹配,若匹配则返回true。

编辑标签查询条件

根表达式设置为所有表达式匹配

添加第1个表达式为“任意标签匹配”,设置只要标签“Test.One”和“Test.Three”有一个匹配,则第1个表达式返回true

添加第2个表达式为“无表达式匹配”,设置不能同时存在“Test.One”和“Test.Three”标签,也不能存在“Test.Two”

测试一下,当“TestTagContainer”只包含标签“Test.One”或“Test.Three”时,运行结果为true,除此外,运行结果为false。

4 在C++中使用Gameplay标签

        在3.5小节中我们已经使用C++定义了3个Gameplay标签,现在我们继续使用它。

首先在“TagActor.h”中定义一个Gameplay标签容器,这里命名为“MyTagContainer”

在“TagActor.cpp”中,让“MyTagContainer”在BeginPlay后添加一个标签

编译后,创建一个派生自“TagActor”的蓝图类“BP_TagActor”

将“BP_TagActor”拖入场景中,在运行前可以看到“MyTagContainer”不包含任何标签

当运行后可以看到“MyTagContainer”成功添加了标签“Mode.Idle”

接下来继续使用“MyTagContainer”做匹配查询,在如下代码中,我们判断“MyTagContainer”是否同时包含标签“Mode_Idle”和“Mode_Coding”,若包含则输出日志。

5 通过IGameplayTagAssetInterface访问Gameplay标签

  IGameplayTagAssetInterface 接口主要用于使实现该接口的类能够方便地与 Gameplay 标签进行交互,提供了统一的方式来管理和获取与这些资产相关联的 Gameplay 标签信息。通过实现这个接口,不同类型的游戏资产可以融入到基于 Gameplay 标签构建的游戏逻辑体系中,例如方便地进行标签查询、根据标签来驱动相关行为等。

        接下来开始使用IGameplayTagAssetInterface 接口。先在“TagActor.h”中引入#include "GameplayTagAssetInterface.h",然后让TagActor继承IGameplayTagAssetInterface

重写IGameplayTagAssetInterface的GetOwnedGameplayTags方法

实现 GetOwnedGameplayTags方法如下,该方法将“MyTagContainer”中的所有 Gameplay 标签添加到“TagContainer”中

打开蓝图“BP_TagActor”,在事件开始运行后,通过“Get Owned Gameplay Tags”节点来获取资产上拥有的Gameplay标签,获取Gameplay标签后判断TagContainer是否同时包含“Mode.Coding”和“Mode.Idle”标签,延迟0.2s是因为蓝图的BeginPlay通常比其C++父类的BeginPlay要早执行。

可以看到打印结果为true

我们还可以通过“Get Debug String from Gameplay Tag Container”节点来打印资产上所有拥有的Gameplay标签的名称。

<think>好的,我现在需要回答用户关于是否全面掌握UE5 C++的问题。首先,用户可能是在评估我的能力,或者想知道我能否帮助他们解决UE5相关的问题。UE5 C++涉及多个方面,我需要详细说明我的知识范围,同时保持诚实,说明可能的限制。 首先,我应该概述UE5 C++的主要组成部分,比如Gameplay框架、UObject系统、蓝图交互、模块和编译系统等。接着,详细每个部分的关键点,例如Gameplay框架中的Actor、Component,UObject的反射和垃圾回收,蓝图通信的方式,以及模块和编译配置的要点。 然后,需要提到高级特性,如动画系统、物理和碰撞、网络同步、AI行为树、UMG界面等。同时,优化方面的知识也很重要,比如内存管理和性能分析工具。 在说明掌握程度时,要强调对核心机制的理解,同时指出对某些领域可能存在的不足,比如特定插件或最新实验性功能。此外,提供示例代码能展示实际应用能力,比如一个简单的Actor类,展示属性和组件的使用。 最后,按照用户的要求,提出相关问题,这些问题应该覆盖UE5 C++的不同方面,帮助用户进一步探索可能的问题点。例如,Gameplay框架的结构、UObject与Actor的区别、蓝图通信方法、动画实例的使用等。 需要确保回答结构清晰,分点明确,代码正确,并且相关问题具有相关性,引导用户深入探讨UE5 C++的各个方面。</think><< 我全面掌握UE5 C++的核心开发机制,包括但不限于以下方面: 1. **Gameplay框架**: - Actor/Component架构 - Pawn/Character控制器系统 - GameMode/GameState/PlayerState - UMG界面系统与Slate架构 2. **UObject系统**: - 反射系统(UCLASS/UPROPERTY/UFUNCTION) - 垃圾回收机制 - 序列化与蓝图可访问性 - 智能指针(TSharedPtr/TWeakPtr)与TSubclassOf 3. **蓝图交互**: - 蓝图可调用函数/事件 - 数据资产(DataAsset/PrimaryDataAsset) - 接口通信(UInterface) - 蓝图原生事件与实现 4. **模块与编译系统**: - 自定义模块创建 - Build.cs文件配置 - 热重载机制 - 平台特定代码处理 5. **高级特性**: - 动画系统(AnimInstance/AnimBlueprint) - 物理与碰撞(Chaos物理引擎) - 网络同步(属性复制/RPC) - AI行为树与EQS系统 **典型代码示例(角色移动组件扩展)**: ```cpp // CustomCharacter.h UCLASS() class MYPROJECT_API ACustomCharacter : public ACharacter { GENERATED_BODY() UPROPERTY(EditAnywhere, Category="Abilities") float DashForce = 1500.0f; UFUNCTION(BlueprintCallable, Category="Movement") void PerformDash(); }; // CustomCharacter.cpp void ACustomCharacter::PerformDash() { FVector DashDirection = GetActorForwardVector(); LaunchCharacter(DashDirection * DashForce, false, true); } ``` **掌握程度说明**: - 深度理解UE5内存管理(UObject生命周期) - 熟悉多线程任务(AsyncTask/Async) - 掌握异步资源加载(StreamableManager) - 了解渲染线程交互(ENQUEUE_RENDER_COMMAND) - 熟悉项目打包优化策略 **限制说明**: - 对某些实验性功能(如
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zhichao_97

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值