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:
PlayMontageAndWaitForEvent是将默认的PlayMontageAndWait和WaitGameplayEvent两种AbilityTasks进行了结合。这可以使用动画蒙太奇利用AnimNotifies给播放他们的GameplayAbility发送事件。使用这种方式在动画蒙太奇播放过程中的特定时间点来触发指定的行为。WaitReceiveDamage会监听OwnerActor接收伤害的事件。被动护甲的GameplayAbility在英雄接收到伤害时移除一层护甲。
AbilityTasks的实现需要有:
- 一个静态函数创建这个
AbilityTask的实例 - 一些委托,绑定到
AbilityTask实现其目标 Activate()函数,以开始其核心任务,绑定外部委托等等OnDestroy()函数,用来进行清理,包括一些绑定的外部委托- 绑定的外部委托的回调函数
- 成员变量和内联的辅助函数
注意:AbilityTasks只能声明一种类型的委托,你的所有的输出委托都必须是这个类型,无论对应的参数是否使用。未使用的委托参数会传递默认值。
AbilityTasks只运行在运行所属GameplayAbility的服务器或者客户端上;但是,AbilityTasks可以通过在构造函数中设置bSimulatedTask = true;,重载virtual void InitSimulatedTask(UGameplayTasksComponent& InGameplayTasksComponent);,并且设定成员变量未复制,从而运行在模拟客户端上。这只用在很少的情况,如模拟运动的AbilityTasks,其中你并不想复制所有的运动变化,而是模拟整个运动的AbilityTask。所有的RootMotionSource的 AbilityTasks都是在做这件事。参阅AbilityTask_MoveToLocation.h/.cpp。
如果你在构造函数中设置bTickingTask = true;并且重写virtual void TickTask(float DeltaTime);的话,AbilityTasks是可以执行Tick类似的工作的。如果你希望去逐帧插值的话,这就非常有用了。参见AbilityTask_MoveToLocation.h/.cpp。
4.7.3 使用技能任务 - Using Ability Tasks
为了在C++中创建和激活AbilityTask(GDGA_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()。

若需要取消某个AbilityTask,只要在蓝图或C++中的AbilityTask对象上(即Async Task Proxy)调用EndTask()即可。
4.7.4 Root Motion Source Ability Tasks
GAS带有一些能够处理角色随时间移动的AbilityTasks,比如角色的击退,复杂的跳跃,拉,冲刺,这些都可以使用Root Motion Sources以及响应的CharacterMovementComponent里的对应功能来实现。
注意: 带预测的RootMotionSource的AbilityTasks在版本4.19和4.25之后的版本可以正常运行,而在4.20-4.24之间的版本是有问题的;但是,AbilityTasks仍然会在多玩家下利用镜像网络矫正来执行其功能,且在单人玩家环境下运行良好。如果要强行使用,建议参考prediction fix。
本文介绍了如何在游戏开发中利用GameplayAbilitiesSystem(GAS)的AbilityTasks来实现技能任务。AbilityTasks允许开发者创建随时间变化的行为,如延迟动作和响应事件。GAS提供了一些预定义的任务,如角色移动、动画播放等,并支持自定义任务,如结合播放动画和等待事件。自定义任务的实现涉及静态创建函数、委托绑定和清理操作。在C++中,通过调用相关函数激活和管理AbilityTasks,而在蓝图中则更简便。此外,RootMotionSource任务可用于处理角色的复杂运动。最后,文章提到了取消任务的方法以及RootMotionSource任务在不同版本中的注意事项。



1116

被折叠的 条评论
为什么被折叠?



