Tizeng's blog Ordinary Gamer

GAS的使用

2022-08-29
Tizeng
GAS

主要参考GASDocument项目。

初始化

ASC需要知道OwnerActor(实际持有ASC的Actor)和AvatarActor(玩家控制的Actor)来初始化,它们可以是同一个,如果我们需要玩家死亡复活后仍旧保留之前的属性等数据,那么ASC一般放在PlayerState上。然后在PossessedBy(服务器)和OnRep_PlayerState(客户端)上分别调用初始化函数InitAbilityActorInfo,它会将ActivatableAbilities中储存的技能设置上Owner。

属性初始化一般是定义一个GE来完成,具体来说就是创建一个默认属性的GE,在Modifiers中配置需要设置的属性类型和值,持续时间设置为Instant,然后配置在对应的角色蓝图上,在ASC和属性集初始化完毕后就可以将其Apply到角色身上。

输入绑定

技能的输入需要单独定义一套InputID,其名称要和ProjectSettings中定义的Input一致,然后在定义GA的时候进行指定,GiveAbility的时候也要用对应的ID去Give,ASC会去监听按键的事件,TryActivate相应的GA。

Meta Attribute(GASDocument 4.3.3)

属性集中可以定义一些占位符(placeholder)属性,称为Meta属性,它的目的是和其他属性进行交互,如常见的伤害,我们把伤害作为一个单独的属性,角色收到伤害时就去修改这个属性,然后属性集中检测到它的变化后就去做处理,如减少HP,这样就可以把伤害计算和伤害处理的逻辑分离开。

冷却GE

技能的cd,输入绑定等通用逻辑,需要放在基类里面,尽管GAS已经把冷却、消耗帮我们做了,但是还是需要一个可以复用的冷却GE,通过Tag去区分每个技能,然后通过SetByCaller的方式去设置其Duration,就可以实现多个GA公用一个冷却GE了。

消耗GE

某个GA可能需要消耗一些属性,比如体力或魔法才能释放,

瞄准GA

开枪GA

开枪的过程可以分为以下几个阶段: 朝目标位置射出子弹 子弹未击中目标 子弹击中目标造成伤害

流星GA

朝指定位置落下一个流星造成范围伤害并眩晕。

AbilityTask

做瞄准的时候GAS文档项目中用到一个TargetActor,它用来指示目前玩家瞄准的位置,使用UAbilityTask_WaitTargetData提供的接口

Demo尝试

射击技能(2022.10.8)

本来分开做了手雷和射箭的GA,完了发现其中很多逻辑是重复的,于是干脆做了一个GA_ShootProjectile,然后手雷和射箭继承它。 射击需要的基本信息如下:

  • Projectile类型
  • 伤害值
  • 伤害Tag
  • 伤害GE
  • 射击的蒙太奇资源

伤害实际上是由ProjectileActor去做,GA在实现Shoot方法时会生成Projectile,然后将与伤害有关的信息放入一个FGameplayEffectSpecHandle,然后Projectile根据自己的逻辑去给目标上这个GE即可。 速度、朝向(velocity)等信息用BlueprintNativeEvent的接口去拿,C++先提供一个默认的,每个具体的Projectile类可以在lua中去实现自己的版本。由于ProjectileMovementComponent的一些逻辑在初始化后就开始执行,我们需要使用延迟Spawn,在信息传递完成后再主动FinishSpawning,保证其使用我们传递的数据。

手雷

手雷在使用ProjectileComponent的时候出现坐标持续变化的情况,是Actor的RootComponent没有规划好导致,StaticMesh开启了物理效果,会被阻挡,而Actor本体其实一直在移动。

弓箭(2022.9.21)

射箭需要播放一个蒙太奇,使用UAbilityTask_PlayMontageAndWait中的接口进行播放,同时得到播放相关的回调,默认它会在EndAbility时停止播放,因此需要掌握好End的时机。 AbilityTask在创建完成初始化,拿到Owner(GA)的TasksComponent,然后在Activate时通过它来告知Owner(GA),GA便会将其存放在ActiveTasks数组中,以便在EndAbility时去告知激活的task去结束。 阅读代码得知这里的TasksComponent其实就是我们的ASC,ASC是其子类,它在这里的作用是同步task的各种状态给Owner处理,与技能本身并无关系,因此作为基类存在。

伤害计算时,每个GA最好对应单独的伤害GE,但是它们可以共用ExecCalc。

遇到的问题

  • 将跳跃做成技能后客户端始终没有表现,只看得到属性变化了,查了半天发现是Activate的时候判断了HasAuthority,因此只在服务器调用了,而文档项目中使用的是HasAuthorityOrPredictionKey
  • 之前HUD放在AHUD里创建,但是那样会找不到ASC,后来在Controller中的OnRep_PlayerState中创建,但是这样Standalone模式走不到,解决方式是在BeginPlay中专门处理Standalone的情况。
  • 之前做UI的时候一直不理解那个Focusable是干嘛的,现在要接入手柄适配了终于理解这个属性的意义,它是为了确定玩家在用键盘、手柄这种外设时正在操作哪个UI,也就是正在Focus哪个UI。
  • AbilityTask在没有手动调用的情况下执行了Activate,后面阅读文档发现是蓝图节点封装了一层调用,外部看不出来
  • 遇到蒙太奇不播放的情况,发现是PlayMontageAndWait接口有一个选项是会在EndAbility后停止播放。
  • 服务器客户端判断在Spawn的时候判断就行了,蒙太奇播放时不用判断,否则客户端看不见效果

  • 服务器上去拿骨骼的Socket信息得到不更新的Pitch值,Yaw却能正常更新?
  • 服务器上生成的Component在BeginPlay时就变成空了?似乎是引擎问题,重启就好了

Similar Posts

上一篇 GAS的基本类型

Comments