4.7 技能任务 - Ability Tasks

4.7.1 技能任务的定义 - Ability Task Definition

GameplayAbilities只能在某一帧执行,这样的机制导致其并没有很大的灵活性。为了实现那些随时间变化的行为,或是在一定时间后响应委托的行为,我们可以使用延迟行为,也即AbilityTasks

GAS自己带了一些可以直接使用的AbilityTasks

  • 基于RootMotionSource的用于角色移动的Task
  • 播放动画蒙太奇的Task
  • 响应Attribute的变化的Task
  • 响应GameplayEffect的变化的Task
  • 响应玩家输入的Task
  • 等等

UAbilityTask的构造函数中硬编码了同一时间最多能够运行1000个并行的AbilityTasks。请谨记,当为游戏设计GameplayAbilities时,像RTS这种游戏可是在某个时间点会同时有上百名角色。

4.7.2 自定义技能任务 - Custom Ability Tasks

你可能会需要创建一些自定义的AbilityTasks(在C++中)。示例项目中建立了两个自定义的AbilityTasks

  1. PlayMontageAndWaitForEvent是将默认的PlayMontageAndWaitWaitGameplayEvent两种AbilityTasks进行了结合。这可以使用动画蒙太奇利用AnimNotifies给播放他们的GameplayAbility发送事件。使用这种方式在动画蒙太奇播放过程中的特定时间点来触发指定的行为。
  2. WaitReceiveDamage会监听OwnerActor接收伤害的事件。被动护甲的GameplayAbility在英雄接收到伤害时移除一层护甲。

AbilityTasks的实现需要有:

  • 一个静态函数创建这个AbilityTask的实例
  • 一些委托,绑定到AbilityTask实现其目标
  • Activate()函数,以开始其核心任务,绑定外部委托等等
  • OnDestroy()函数,用来进行清理,包括一些绑定的外部委托
  • 绑定的外部委托的回调函数
  • 成员变量和内联的辅助函数

注意:AbilityTasks只能声明一种类型的委托,你的所有的输出委托都必须是这个类型,无论对应的参数是否使用。未使用的委托参数会传递默认值。

AbilityTasks只运行在运行所属GameplayAbility的服务器或者客户端上;但是,AbilityTasks可以通过在构造函数中设置bSimulatedTask = true;,重载virtual void InitSimulatedTask(UGameplayTasksComponent& InGameplayTasksComponent);,并且设定成员变量未复制,从而运行在模拟客户端上。这只用在很少的情况,如模拟运动的AbilityTasks,其中你并不想复制所有的运动变化,而是模拟整个运动的AbilityTask。所有的RootMotionSourceAbilityTasks都是在做这件事。参阅AbilityTask_MoveToLocation.h/.cpp

如果你在构造函数中设置bTickingTask = true;并且重写virtual void TickTask(float DeltaTime);的话,AbilityTasks是可以执行Tick类似的工作的。如果你希望去逐帧插值的话,这就非常有用了。参见AbilityTask_MoveToLocation.h/.cpp

4.7.3 使用技能任务 - Using Ability Tasks

为了在C++中创建和激活AbilityTaskGDGA_FireGun.cpp),需要做:

UGDAT_PlayMontageAndWaitForEvent* Task = UGDAT_PlayMontageAndWaitForEvent::PlayMontageAndWaitForEvent(this, NAME_None, MontageToPlay, FGameplayTagContainer(), 1.0f, NAME_None, false, 1.0f);
Task->OnBlendOut.AddDynamic(this, &UGDGA_FireGun::OnCompleted);
Task->OnCompleted.AddDynamic(this, &UGDGA_FireGun::OnCompleted);
Task->OnInterrupted.AddDynamic(this, &UGDGA_FireGun::OnCancelled);
Task->OnCancelled.AddDynamic(this, &UGDGA_FireGun::OnCancelled);
Task->EventReceived.AddDynamic(this, &UGDGA_FireGun::EventReceived);
Task->ReadyForActivation();

在蓝图中,我们仅需要使用为AbilityTask而构建的蓝图节点即可。而且不需要去调用ReadyForActivate()。它会由Engine/Source/Editor/GameplayTasksEditor/Private/K2Node_LatentGameplayTaskCall.cpp自动调用。如果在你的AbilityTask类中有BeginSpawningActor()FinishSpawningActor()的话,K2Node_LatentGameplayTaskCall也将其自动调用(参见AbilityTask_WaitTargetData)。这里再强调一遍,K2Node_LatentGameplayTaskCall仅仅针对蓝图做了这些神奇的操作。在C++中,我们还是需要手动调用ReadyForActivation()BeginSpawningActor()以及FinishSpawningActor()

Blueprint WaitTargetData AbilityTask

若需要取消某个AbilityTask,只要在蓝图或C++中的AbilityTask对象上(即Async Task Proxy)调用EndTask()即可。

4.7.4 Root Motion Source Ability Tasks

GAS带有一些能够处理角色随时间移动的AbilityTasks,比如角色的击退,复杂的跳跃,拉,冲刺,这些都可以使用Root Motion Sources以及响应的CharacterMovementComponent里的对应功能来实现。

注意: 带预测的RootMotionSourceAbilityTasks在版本4.19和4.25之后的版本可以正常运行,而在4.20-4.24之间的版本是有问题的;但是,AbilityTasks仍然会在多玩家下利用镜像网络矫正来执行其功能,且在单人玩家环境下运行良好。如果要强行使用,建议参考prediction fix

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值