|
原文:
兼容联网环境的 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
- K2_EndAbility()
- 受击触发
- OnComponentBeginOverlap
- HasAuthority
- UAbilitySystemComponent::ApplyGameplayEffectSpecToSelf
- 表现:血条更新
- UAbilitySystemComponent::GetGameplayAttributeValueChangeDelegate
- UIFloatingStatusBar->SetHealthPercentage(GetHealth() / GetMaxHealth());
- 伤害掉血
- UGameplayEffectExecutionCalculation:Execute
- 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配置受击特效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 就好,是同步的。
相关链接 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|