BlueRoseNote/03-UnrealEngine/Gameplay/GAS/(13)附魔与宝石系统实现与给GE GA传参方法.md
2023-06-29 11:55:02 +08:00

5.6 KiB
Raw Blame History

DataAsset与UObject

数据资产的巨大优势在于,你可以将它们设置为自动在引擎中注册,所以每次你添加一个新的数据资产时,引擎都会自动将其添加到一个列表中。因此,如果你的武器是数据资产,当你在游戏中添加一个新的武器时,它就会自动添加到一个你可以搜索的列表中,所以你不需要每次添加一个新的武器时在你的代码中手动添加绑定。

如果不需要这种类型的东西,把它变成数据资产就没有什么好处。

附魔

附魔分为临时附魔与永久附魔。临时附魔以Buffer的方式存在其Handle存储在角色类中。永久附魔应用后的Handle则存储在所依附的物品类武器或者身上的其他装备用于解除装备后去除GE。

存在问题

  1. 如果武器存在属性,附魔也存在属性,那伤害该如何计算?

宝石(镶嵌物)

镶嵌在有限的武器槽中,增加角色属性或者改变武器(攻击)属性。

实现方式

在创建新的 Inlay 物品类里面存储GameplayEffect用于调整角色属性与武器攻击属性。应用后的Handle存储在所依附的物品类武器或者身上的其他装备用于解除装备后去除GE。

武器的镶嵌物与附魔的初始信息存储在DataAsset中而玩家runtime与存档信息则通过实例化的URPGWeaponItem来存储。WeaponActor保存对应的GEHandle数据全都是临时性的实现对应的方法。

GASDocument的武器数值实现

  • 在物品上使用原始数值变量(推荐)
  • 在物品类上使用独立的AttributeSet
  • 在物品类上使用独立的ASC

具体可以参考GASShooter项目。不使用AttributeSet直接将数值存在在武器类或者GameplayABility中内。

运行时添加与移除属性级

//On weapon add to inventory:
AbilitySystemComponent->SpawnedAttributes.AddUnique(WeaponAttributeSetPointer);
AbilitySystemComponent->ForceReplication();

//On weapon remove from inventory:
AbilitySystemComponent->SpawnedAttributes.Remove(WeaponAttributeSetPointer);
AbilitySystemComponent->ForceReplication();

各个方案的好处与坏处

使用原始数值变量 好处:

  • 避免使用限制AttributeSets见下文 限制:
  • 无法使用现有GameplayEffect工作流程Cost GEs用于弹药等
  • 需要工作来覆盖关键功能UGameplayAbility以检查和应用弹药成本对枪支的浮标

使用独立的AttributeSet 好处:

  • 可以使用现有GameplayAbility和GameplayEffect工作流程Cost GEs用于弹药等
  • 设置非常小的项目集很简单 限制: -您必须AttributeSet为每种武器类型创建一个新类。ASCs只能在功能上拥有一个AttributeSet类的实例因为更改为在数组中Attribute查找其AttributeSet类的第一个实例ASCs SpawnedAttributes。同一AttributeSet类的其他实例将被忽略。
  • 由于之前AttributeSet每个AttributeSet类一个实例的原因您只能在玩家的库存中拥有每种类型的武器之一。
  • 删除 anAttributeSet是危险的。在 GASShooter 中,如果玩家从火箭中自杀,玩家会立即从他的物品栏中移除火箭发射器(包括 中AttributeSet的ASC。当服务器复制火箭发射器的弹药Attribute改变时AttributeSet客户端上不再存在ASC游戏崩溃。

构造GameplayEffect并且修改参数

DamageEffectSpecHandle存储着FGameplayEffectSpec的智能指针。通过MakeOutgoingGameplayEffectSpec创建并且修改参数之后再通过ApplyGameplayEffectSpecToTarget应用到指定目标。

UPROPERTY(BlueprintReadOnly, EditAnywhere)
TSubclassOf<UGameplayEffect> DamageGameplayEffect;
FGameplayEffectSpecHandle DamageEffectSpecHandle = MakeOutgoingGameplayEffectSpec(DamageGameplayEffect, GetAbilityLevel());
// Pass the damage to the Damage Execution Calculation through a SetByCaller value on the GameplayEffectSpec
DamageEffectSpecHandle.Data.Get()->SetSetByCallerMagnitude(FGameplayTag::RequestGameplayTag(FName("Data.Damage")), Damage);

动态创建GE并且应用

// Create a dynamic instant Gameplay Effect to give the bounties
UGameplayEffect* GEBounty = NewObject<UGameplayEffect>(GetTransientPackage(), FName(TEXT("Bounty")));
GEBounty->DurationPolicy = EGameplayEffectDurationType::Instant;

int32 Idx = GEBounty->Modifiers.Num();
GEBounty->Modifiers.SetNum(Idx + 2);

FGameplayModifierInfo& InfoXP = GEBounty->Modifiers[Idx];
InfoXP.ModifierMagnitude = FScalableFloat(GetXPBounty());
InfoXP.ModifierOp = EGameplayModOp::Additive;
InfoXP.Attribute = UGDAttributeSetBase::GetXPAttribute();

FGameplayModifierInfo& InfoGold = GEBounty->Modifiers[Idx + 1];
InfoGold.ModifierMagnitude = FScalableFloat(GetGoldBounty());
InfoGold.ModifierOp = EGameplayModOp::Additive;
InfoGold.Attribute = UGDAttributeSetBase::GetGoldAttribute();

Source->ApplyGameplayEffectToSelf(GEBounty, 1.0f, Source->MakeEffectContext());

持续刷新GE以延长持续时间

4.5.16 修改已激活GameplayEffect的持续时间

AGameplayAbilityTargetActor

4.11.1 Target Data 4.11.2 Target Actor 用于获取场景中的信息,或者在场景中生成一些东西。

Input绑定

如果你的ASC位于Character, 那么就在SetupPlayerInputComponent()中包含用于绑定到ASC的函数.

GASDocument上常用的Abilty和Effect

  1. 眩晕(Stun)
  2. 奔跑(Sprint)
  3. 瞄准(Aim Down Sight)
  4. 生命偷取(Lifesteal)
  5. 在客户端和服务端中生成随机数
  6. 暴击(Critical Hits)
  7. 非堆栈GameplayEffect, 但是只有其最高级(Greatest Magnitude)才能实际影响Target
  8. 游戏暂停时生成TargetData
  9. 按钮交互系统(Button Interaction System)