欢迎您光临本站,秉承服务宗旨,履行"站长"责任,销售只是起点,服务永无止境!
也想出现在这里? 联系我们

为什么要在虚幻引擎中使用GameplayTags?

作者 : qwe789 本文共4571个字,预计阅读时间需要12分钟 发布时间: 2023-01-31 共2.41K人阅读

你可能熟悉也可能不熟悉虚幻引擎中的游戏标签。它在虚幻引擎的游戏能力系统中大量使用,但可以在游戏框架中单独使用。在本文中,我将介绍 GameplayTags 以及如何在您的游戏中使用它们,即使您选择不使用 GAS。

什么是游戏标签?

游戏标签基本上是在游戏项目设置中定义的 FNames。使用这些标签的一个主要好处是,它们允许在编辑器的UI中轻松选择,并通过GameplayTagContainers(具有许多帮助程序函数的GameplayTags数组)组合多个标签。您不要将 TArray 与 FGameplayTag 一起使用,相反,您应该始终使用 GameplayTagContainer,因为它具有帮助程序函数,可以轻松匹配一个或多个标签。

另一个功能是用于查找确切标签或其父级的层次结构。这使您可以创建从宽到非常窄的标记树。一些例子:

  • 伤害.DoT.火灾
  • 位置.星球.废弃
  • 操作.主要 / 操作.次要
  • Effect.Burning / Effect.UIHidden
  • 损坏类型.能量
  • 属性.健康
  • 码头工程

以上是我自己的一些项目中使用的随机选择的标签。巧妙的是,您可以使用GameplayTags来指定某些内容是DamageType,更具体地说是DamageType.Fire,DamageType.Kinetic等。

一旦您开始以这种方式考虑您的内容并在一些实际场景中使用它,层次结构的概念可能会变得更加清晰。我花了一点时间才终于了解如何正确使用此功能。

游戏标签与演员/组件标签有何不同?

虚幻引擎中有两个标记系统可能会令人困惑。标签的基本系统(Actor/Component Tags)与字符串一起工作,并且没有GameplayTags的简洁功能。一旦您的内容开始在数百个游戏资产中增长,您真的不希望手写字符串标签中出现拼写错误,或者在整个内容文件夹中重新打开资产以记住您如何命名该特定标签,因为基本标签系统没有中央数据库。该系统还缺少层次结构功能。使用这个基本系统管理和比较标签将成为一场噩梦。

一些实际用例

考虑标签的一种方法是拥有一个庞大的布尔值库。你可以轻松地用各种各样的“布尔值”来装饰你的Actor(以及大多数其他类型的内容),以便你的游戏代码的其余部分阅读和反应。这里的主要好处是,当使用 ActorComponent 来保存这些标记时,您不需要像使用常规布尔变量那样强制转换为特定的 Actor (基)类。它比你必须将 100 个布尔值编译到你的(基)类中要动态得多。

我强烈建议您研究Epic的ActionRPG,以熟悉游戏能力系统及其对GameplayTags的使用。它使用组件添加到特定于游戏玩法的Actor中,您可以使用游戏标签加载这些Actor。我自己的开源项目使用GameplayTags作为自定义能力系统和锁定和钥匙示例。

我自己的游戏框架中的一些例子:

  • 通过标签而不是类引用启动技能/动作。这些能力可以应用于角色,而不是强制转换为特定的能力类 - 如果存在该技能,您可以使用标签来执行查找和执行。避免硬引用的简单方法,并且不需要特定的类。多个能力可以使用相同的“Action.PrimaryAttack”标签。
  • 传入游戏标签作为事件的参数,为发生的游戏触发器提供额外的上下文。

我将在C++部分的下方的“C++中的游戏标签”中展示上下文标签的示例。这种情况非常有助于为游戏代码提供额外的信息,而不会最终得到大量独特的函数签名和太多的参数来管理,而不是使用单个 FGameplayTagContainer 参数。该示例在收到的伤害是暴击时添加一个“CritTag”,并且游戏或 UI 应相应地做出响应。

为什么要在虚幻引擎中使用GameplayTags?
添加 GameplayTag 侦听器对于构建事件驱动的游戏框架非常宝贵。在这里,我们监听Pawn进入ADS(瞄准瞄准),以便我们可以运行一些逻辑来响应。(注意:AddGameplayTagListener 是我自己项目中的一个函数——类似的功能可以在 GAS 中找到)
为什么要在虚幻引擎中使用GameplayTags?
将键存储为游戏标签的自定义黑板类。在这里,我们开始侦听对特定密钥的更改。(带有AddListener的全局黑板是我自己项目中的另一个例子)
为什么要在虚幻引擎中使用GameplayTags?
我的游戏WARPSQUAD的另一个例子。在这里,我们从游戏组件中获取一个“属性”,例如健康,在本例中为标签散热。
为什么要在虚幻引擎中使用GameplayTags?
同样,我们可以通过游戏标签进行修改。

使用标签标记您的战利品表,这些标签可以阻止特定物品掉落在表中或掉落特定物品所需的标签。

为什么要在虚幻引擎中使用GameplayTags?
“必需标签”可用于在掷骰子之前从战利品表中过滤掉物品。这些“标签”可以从游戏代码中的任何位置抓取,例如应用于角色、掠夺宝箱、环境等的标签。
为什么要在虚幻引擎中使用GameplayTags?
FGameplayTagQuery(上面的“标签查询”)可用于更复杂的标签比较,以匹配层次结构和多个标签。

 

游戏标签作为投射的替代品

在项目后期之前,强制转换和类引用不会成为问题。您将意识到任何类硬引用都需要加载类/蓝图,这可能会导致加载一系列其他资源,例如网格或粒子效果。您可以(并且应该)使用尽可能不引用其他资产的基类来减少此问题。GameplayTags 允许您删除资产之间的更直接引用,从而提供更多帮助。

检查参考的最佳方法是使用参考查看器和大小地图工具。(两者都可以通过在内容浏览器中右键单击您的资产来获得)

为什么要在虚幻引擎中使用GameplayTags?

在上面的例子中,我已经看到了一些不应该存在的引用。我们不知何故最终引用了一个大小为 11MB 的炮塔旋转类(左),应该与玩家棋子无关。这些问题通常会在开发过程中发生,最好尽早发现这些问题,因为您可能需要在项目为时已晚之前调整框架设计或更改编码习惯。这不仅仅是针对最终的游戏产品,只要您启动编辑器或加载您处理的特定蓝图(及其所有引用),您就会加载这些引用的资源。

此处引用的任何资产都将在使用相关资产时加载——除非您在所述资产中使用软引用。这是一个无声的杀手,因为直到你已经添加了相当多的内容,你才会注意到,此时重新设计你的框架是很昂贵的。

用标签装饰物品

我的游戏有大量的“物品”,这些物品不仅限于你认为的物品栏中的物品。甚至兴趣点、角色、船只、成就等也可以被视为物品。实际上,它是一个(主要)数据资产,包含显示信息、能力数据、相关 Actor 类、游戏标签等。游戏标签可用于通常使用上下文中所需的任何信息装饰您的“物品”。

为什么要在虚幻引擎中使用GameplayTags?
WARPSQUAD中的一些当前物品类型。

网络(复制)

虚幻引擎可以比FNames更有效地复制GameplayTags。“项目设置”>“游戏标签”中提供了一些选项。“快速复制”能够按索引而不是全名复制标签,为此,客户端和服务器之间的标签列表必须相同。

为什么要在虚幻引擎中使用GameplayTags?

游戏能力系统

FGameplayTag计数容器添加了计算添加特定标记的次数的功能。当多个源可能添加/删除标签时,这非常有用。这样,你们每个人都可以做自己的事情而不会发生冲突。理想情况下,这将内置于常规的FGameplayTagContainer中,并且您也不能独立使用它,因为它在内部引用了能力系统。我最终在自己的框架中重新创建了这个计数容器。

GameplayTag添加/删除侦听器是另一个简洁的功能,我也在自己的框架中广泛使用。每当某个Actor被添加刻录标签以启动你的火焰FX或触发其他系统反应时,请收听。

游戏能力系统有更多的技巧和隐藏的宝石。例如,如果您正在寻找结构的自定义网络序列化,请查看 FGameplayEffectContext 行 177 NetSerialize()。

在C++项目中启用游戏标签。

要在C++中启用GameplayTags的使用,您必须将“GameplayTags”模块添加到MyProject.build.cs。单击此处查看启用了 GameplayTags 的 *.builds.cs 示例。

确保启用了“游戏标签编辑器”插件(默认)。否则,您将没有任何有用的编辑器窗口使其如此有用。

C++中的游戏标签示例

理想情况下,您不会在C++中对标签进行硬编码,但在某些情况下,例如游戏损害计算功能,这是有意义的。下面是来自此类函数的一些代码,其中请求标签并将其添加为“上下文”。

// General Tags
static FGameplayTag DamagePassthroughTag = FGameplayTag::RequestGameplayTag("Damage.PassToParent");
// DamageTypes
static FGameplayTag KineticDamageTag = FGameplayTag::RequestGameplayTag("DamageType.Kinetic");
static FGameplayTag EnergyDamageTag = FGameplayTag::RequestGameplayTag("DamageType.Energy");
// Armor Plates
static FGameplayTag ArmorTag = FGameplayTag::RequestGameplayTag("Damage.Armor");

通过使用“静态”,我们只需要运行一次此请求,下次我们需要它时它会保留下来。这很棒,因为此标签无法更改或无效。

ULZGameSubsystem* Subsystem = UGameInstance::GetSubsystem<ULZGameSubsystem>(GetWorld()->GetGameInstance());
if (Subsystem->GetRandomFloat(0, 99.f, "CritDamage") < CritChancePerc)
{
  Context.ContextTags.AddTag(CritTag);
  //...
}

这里的“ContextTags”是一个FGameplayTagContainer,位于另一个被传递的结构“Context”中。游戏代码和 UI 可以从此上下文中读取并更改其行为。例如,在“暴击”期间,我们在UI中显示的伤害数字与常规命中略有不同。

定义原生游戏标签

从 4.27 开始,直接在 C++ 中定义游戏标签要容易得多。如果您的框架要求存在某些标记,而不必在 INI 文件中的其他地方定义它们,这会很有帮助。然后,您不需要使用前面的 RequestGameplayTag() 函数,只要您在代码而不是 INI 中定义了此标记即可。

// Macro in your CPP file, naming style is an example. First param is what you use to access this Tag in your C++.
UE_DEFINE_GAMEPLAY_TAG(TAG_Attribute_Health, "Attribute.Health");

// In the Header file.
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Attribute_Health);

// -- Alternative Macro is available: --- //

/**
 * Defines a native gameplay tag such that it's only available to the cpp file you define it in.
 */
UE_DEFINE_GAMEPLAY_TAG_STATIC(TAG_Attribute_Health, "Attribute.Health");

 

版权声明:
本站所有文章、资源等一切内容,皆为在本站的注册网友所发布、上传、提供,如您发现任何内容侵犯了您的合法权益, 请与我们联系 ,我们将第一时间进行清理。iiiue.com 旨在为广大虚幻引擎爱好者提供技术交流学习、知识技术变现平台。
永久域名 iii ue .com 本站投稿能赚取收益变现提现,请一定要牢记账号密码!
Ue资源站 iiiue.com » 为什么要在虚幻引擎中使用GameplayTags?

常见问题FAQ

免费下载或者VIP会员专享资源能否直接商用?
本站所有内容皆为网友发布,资源版权均属于原作者所有,如需商用请联系原作者获取授权许可,若由于商用引起版权纠纷,一切责任均由使用者承担。如您发现某些内容侵犯了您的合法权益, 请与我们联系 ,我们将在第一时间核实并清理。
下载的资源解压密码是多少?
任何资源的解压密码均由发布者提供,一般情况下都在资源的发布页面或者资源文件夹,请仔细检查,如您发现发布页面没有提供解压密码,请您试着在评论处留言联系作者,或者复制以下两个密码进行解压,或许会有意想不到的效果。
iiiue.com
ue5club
Tips:除了密码说明内的解压密码外,通常情况下,电脑在安装好RAR或360解压缩软件,双击打开压缩包,包内注释的网址也可以试试是否为解压密码哦
资源能否免费获取
本站用户可参与站内的一系列活动获取积分,资源皆可免费获取,若想快速获取可加入本站永久VIP钻石会员,荣耀身份,全站资源免费获取, 点此查看详情

发表回复

也想出现在这里? 联系我们
开通终身VIP 永久VIP折扣活动火热进行中,享全站资源免费下载特权!