兼容联网环境的 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]