## 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 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(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)