ChuanXin 发表于 2022-12-18 18:13

兼容联网环境的 Unreal 战斗攻受击全流程使用实践总结

原文:

兼容联网环境的 Unreal 战斗攻受击全流程使用实践总结
前言

背景


[*]根据 GAS 官方教程和工程 GASDocumentation ,参考已有技能和逻辑,在新工程中搭建了联网环境,并添加了自己的技能和相关逻辑,测试通过。
目的


[*]记录

[*]   记录一种可行的、较为标准的、官方推荐的、支持联网和单机的技能攻受击流程,包括主动技能、被动技能、技能 Cost、技能 Cooldown、攻击动作、攻击效果、受击动作、受击效果、掉血扣蓝等一般的战斗技能流程中的通用表现或逻辑。

[*]分享

[*]   网上有较多 GAS 的教程,但大部分是单机下的,对于联网环境,不一定适用。本文基于验证过的网络环境(DS、P2P、Standalone均测试过),会特别记录下一些关键配置和流程。

说明


[*]本文主要参考 GAS 官方工程 GASDocumentation 及网络和官方的文档,虽为验证过的流程,但亦不代表这是标准联网开发的战斗流程,更不是唯一正确实践路线,也不是最佳路线。
[*]本文不会讨论研究 GAS 底层原理乃至概念,也不会深入讨论网络同步,只会从实战使用角度对全流程做说明,尽量让初学者在初步了解了GAS相关概念之后能系统地跑起来一个自己的技能。
效果



https://www.zhihu.com/video/1579965830376374273
全流程

全流程详细说明图




解释说明


[*]初始化

[*]   UAbilitySystemComponent::InitAbilityActorInfo
[*]   ASQCharacterBase::InitializeAttributes

[*]   初始化血量、等级、血量回复速度等初始 GE
[*]   通过 UAbilitySystemComponent::MakeOutgoingSpec 创建 FGameplayEffectSpecHandle
[*]   再通过 UAbilitySystemComponent::ApplyGameplayEffectSpecToTarget 赋予目标

[*]   SetHealth(GetMaxHealth())

[*]   设置初始属性,如让血量为最大值
[*]   实际调用的是 USQAttributeSetBase 里
[*]   通过 ATTRIBUTE_ACCESSORS 定义的 Health 等属性的 Set

[*]   UAbilitySystemComponent::GetGameplayAttributeValueChangeDelegate;

[*]    监听属性如HP等的变化,
[*]    方便后文处理血条等和HUD等的表现。

[*]   ASQCharacterBase::AddStartupEffects

[*]    添加当前属性如HP等的初始GE
[*]    实现方式跟上方的 InitializeAttributes 一样

[*]   UAbilitySystemComponent::GiveAbility

[*]    赋予技能

[*]   所有相关技能都要先 GiveAbility (不是 ActivateAbility )
[*]   可以在 ASQCharacterBase 中把所有技能初始化
[*]   GiveAbility 时可以指定让技能与输入绑定



[*]攻击

[*]   ActivateAbility

[*]    技能通过初始化时绑定的按键等输入主动触发
[*]    也可以被动触发,见后文

[*]   CommitAbility

[*]    判断校验,触发 GA 上配置的 Cost和Cooldown GE
[*]    扣除对应的蓝,并让技能处于 CD

[*]   CreatePlayMontageAndWaitProxy

[*]    播放攻击动画
[*]    BP和C++的接口略有不同,但底层一致
[*]    如为C++,还需调用:
[*]    UAbilityTask_PlayMontageAndWait::Activate

[*]   SpawnActor

[*]    BP或C++生成带碰撞的子弹或攻击物

[*]   K2_EndAbility()

[*]    结束攻击GA
[*]    BP中为 EndAbility


[*]受击触发

[*]   OnComponentBeginOverlap

[*]    (以子弹攻击为例)子弹击中目标

[*]   HasAuthority

[*]    先判断是否有权限

[*]   UAbilitySystemComponent::ApplyGameplayEffectSpecToSelf

[*]    对目标施加伤害GE和其它GE(如BUFF等)


[*]表现:血条更新

[*]   UAbilitySystemComponent::GetGameplayAttributeValueChangeDelegate

[*]   在角色 BeginPlay 时监听属性变化

[*]   UIFloatingStatusBar->SetHealthPercentage(GetHealth() / GetMaxHealth());

[*]   在收到属性变化的通知时,让血条等更新


[*]伤害掉血

[*]   UGameplayEffectExecutionCalculation:Execute

[*]    伤害GE配置的 Execution GE 执行

[*]   Execute_Implementation;

[*]    在执行回调中写逻辑

[*]   FGameplayEffectCustomExecutionParameters::AttemptCalculateCapturedAttributeMagnitude;
[*]   FGameplayEffectSpec::GetSetByCallerMagnitude;

[*]    获取防御和伤害

[*]   FGameplayEffectCustomExecutionOutput::AddOutputModifier;

[*]    施加属性变化


[*]收到属性变化的处理

[*]   USQAttributeSetBase::PostGameplayEffectExecute
[*]   Data.EvaluatedData.Attribute == GetDamageAttribute()

[*]    根据属性标志来采取对应措施

[*]   Data.Target.AbilityActorInfo->AvatarActor.Get()

[*]    拿到目标


[*]让目标播放受击动画

[*]   PlayHitReact

[*]    这个方法必须是可靠广播
[*]    UFUNCTION(NetMulticast, Reliable, WithValidation)

[*]   PlayHitReact_Implementation;

[*]    目标收到受击广播

[*]   UAbilitySystemBlueprintLibrary::SendGameplayEventToActor

[*]    通过 GameplayEvent 来触发受击 GA (配置方式见说明)


[*]受击GA:

[*]播放受击动画(参考攻击)
[*]UGameplayAbility::BP_ApplyGameplayEffectToOwner

[*]给目标添加受击GE

[*]受击GE配置受击特效GC(配置方式见说明)
[*]受击GC在GE触发时执行其 OnActive 等,在其中生成特效等

[*]血量等属性变化

[*]   USQAttributeSetBase Healtht

[*]    属性必须是同步的,有配置变化回调
[*]    UPROPERTY(BlueprintReadOnly, Category = "Health", ReplicatedUsing = OnRep_Health)

[*]   OnRep_Health;

[*]    收到属性变化
[*]    通过 GAMEPLAYATTRIBUTE_REPNOTIFY(USQAttributeSetBase, Health, OldHealth) 来触发属性调整 FActiveGameplayEffectsContainer::SetBaseAttributeValueFromReplication
[*]    更深入的底层此处略


问题答疑


[*] 关于联网下被动技能的配置和触发

[*]对于被动技能 GA, 首先配置其 Trigger Tag 为受击 Tag
[*]然后选择 Trigger Source 为 Gameplay Event





[*]【特别注意】在 USQAttributeSetBase::PostGameplayEffectExecute 回调中,调用受击目标角色身上的 Reliable 方法 TargetCharacter->PlayHitReact 。





[*]在 PlayHitReact 的网络回调 PlayHitReact_Implementation 中,调用 UAbilitySystemBlueprintLibrary::SendGameplayEventToActor(this, HitTag, FGameplayEventData()) 去触发目标身上的被动 GA 。
[*]如是才能让技能成功执行,动作成功播放。否则被动技能可能不会执行,或执行之后没效果。

[*] 关于主动技能无法再次触发

[*]查看其是否配置了自身被自身技能 tag block,且其 cooldown 里是不是配置了 grade 自身的 skill tag

[*] 关于伤害很小的子弹类技能把敌方秒杀了

[*]施加伤害GE是否是在子弹的碰撞逻辑中?如果是的话,打日志或debug一下看看是否在子弹销毁前有重复执行伤害GE施加。

[*] 关于 UProjectileMovementComponent 生成的子弹不朝向目标飞行?

[*]UProjectileMovementComponent 的 Velocity 3个值全部重置为0。

[*] 关于参考 GASDocumentation 做的子弹能生成但是不产生伤害。

[*]如果子弹的伤害逻辑也是参考的 GASDocumentation ,则检查 SpawnActor时候 Instigator 要设置为技能发送者,而不是技能受击者。因为其逻辑中会判断 Instigator 决定是否产生伤害。

[*]关于 GC 无效果

[*]对应GE : DurationPolicy 必须配置为 has duration, magnitude attribute 设置 calculationtype 为 scalable float,值不为 0 , gameplay cues 里配置对应的 gameplay cue tags

[*]C++ 中 WaitTargetData 不响应确认按键

[*]C++中的 AbilityTask需要手动调用ReadyForActivation(), BeginSpawningActor(), 和 FinishSpawningActor()。
[*]BeginSpawningActor 会生成一个 actor,传给FinishSpawningActor 就好,是同步的。

相关链接
页: [1]
查看完整版本: 兼容联网环境的 Unreal 战斗攻受击全流程使用实践总结