167 lines
6.5 KiB
Markdown
167 lines
6.5 KiB
Markdown
|
## UAbilityTask
|
|||
|
UAbilityTask继承自UGameplayTask(UGameplayTask可以用来写一些行为树中的一些节点),可以用来实现一些异步功能。比如播放montage后各种事件的处理。
|
|||
|
|
|||
|
你可以去GameplayAbilities\Public\Abilities\Tasks\目录下寻找作者编写的task类作为相关参考,也可以直接使用(GameplayTasks目录下的案例比较少)。
|
|||
|
|
|||
|
当然我更加推荐学习actionRPG项目中的PlayMontageAndWaitForEvent,原因有:1、这个task用得最多2、涉及Task的代码相对较多。
|
|||
|
|
|||
|
其他推荐学习的:UGameplayTask_WaitDelay、UAbilityTask_WaitGameplayEvent、UAbilityTask_WaitGameplayTagAdded、UAbilityTask_WaitGameplayEffectApplied
|
|||
|
## 大致过程
|
|||
|
1. 声明多个动态多播委托用于处理各种事件。
|
|||
|
2. 重写所需的虚函数,并且声明相关变量。
|
|||
|
3. 编写主体函数。
|
|||
|
|
|||
|
## 代码分析
|
|||
|
在PlayMontageAndWaitForEvent中重写了4个虚函数:
|
|||
|
```
|
|||
|
//用于在各种委托设置完毕后开始执行真正的Tasks。
|
|||
|
virtual void Activate() override;
|
|||
|
|
|||
|
//从外部取消这个Tasks,默认情况下,会结束任务。
|
|||
|
virtual void ExternalCancel() override;
|
|||
|
|
|||
|
//返回debug字符串,内容为当前播放的Montage名称以及Tasks存储的Montage名称
|
|||
|
virtual FString GetDebugString() const override;
|
|||
|
|
|||
|
//结束并清理Tasks,既可以在Tasks内部调用,可以从该Tasks拥有者调用。
|
|||
|
//注意:请不要直接调用该函数,你应该调用EndTask()或者TaskOwnerEnded()
|
|||
|
//注意:重写该函数时,请确保最后调用Super::OnDestroy(bOwnerFinished)
|
|||
|
virtual void OnDestroy(bool AbilityEnded) override;
|
|||
|
```
|
|||
|
## Activate()
|
|||
|
```
|
|||
|
void URPGAbilityTask_PlayMontageAndWaitForEvent::Activate()
|
|||
|
{
|
|||
|
if (Ability == nullptr)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
bool bPlayedMontage = false;
|
|||
|
URPGAbilitySystemComponent* RPGAbilitySystemComponent = GetTargetASC();
|
|||
|
|
|||
|
if (RPGAbilitySystemComponent)
|
|||
|
{
|
|||
|
const FGameplayAbilityActorInfo* ActorInfo = Ability->GetCurrentActorInfo();
|
|||
|
UAnimInstance* AnimInstance = ActorInfo->GetAnimInstance();
|
|||
|
if (AnimInstance != nullptr)
|
|||
|
{
|
|||
|
//绑定事件回调函数
|
|||
|
EventHandle = RPGAbilitySystemComponent->AddGameplayEventTagContainerDelegate(EventTags, FGameplayEventTagMulticastDelegate::FDelegate::CreateUObject(this, &URPGAbilityTask_PlayMontageAndWaitForEvent::OnGameplayEvent));
|
|||
|
|
|||
|
//播放montage
|
|||
|
if (RPGAbilitySystemComponent->PlayMontage(Ability, Ability->GetCurrentActivationInfo(), MontageToPlay, Rate, StartSection) > 0.f)
|
|||
|
{
|
|||
|
//播放Montage后,其回调函数可能会导致Ability结束,所以我们需要提前结束
|
|||
|
if (ShouldBroadcastAbilityTaskDelegates() == false)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
//绑定OnAbilityCancelled
|
|||
|
CancelledHandle = Ability->OnGameplayAbilityCancelled.AddUObject(this, &URPGAbilityTask_PlayMontageAndWaitForEvent::OnAbilityCancelled);
|
|||
|
//绑定OnMontageBlendingOut
|
|||
|
BlendingOutDelegate.BindUObject(this, &URPGAbilityTask_PlayMontageAndWaitForEvent::OnMontageBlendingOut);
|
|||
|
AnimInstance->Montage_SetBlendingOutDelegate(BlendingOutDelegate, MontageToPlay);
|
|||
|
//绑定OnMontageEnded
|
|||
|
MontageEndedDelegate.BindUObject(this, &URPGAbilityTask_PlayMontageAndWaitForEvent::OnMontageEnded);
|
|||
|
AnimInstance->Montage_SetEndDelegate(MontageEndedDelegate, MontageToPlay);
|
|||
|
|
|||
|
ACharacter* Character = Cast<ACharacter>(GetAvatarActor());
|
|||
|
if (Character && (Character->Role == ROLE_Authority ||
|
|||
|
(Character->Role == ROLE_AutonomousProxy && Ability->GetNetExecutionPolicy() == EGameplayAbilityNetExecutionPolicy::LocalPredicted)))
|
|||
|
{
|
|||
|
Character->SetAnimRootMotionTranslationScale(AnimRootMotionTranslationScale);
|
|||
|
}
|
|||
|
|
|||
|
bPlayedMontage = true;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ABILITY_LOG(Warning, TEXT("URPGAbilityTask_PlayMontageAndWaitForEvent call to PlayMontage failed!"));
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ABILITY_LOG(Warning, TEXT("URPGAbilityTask_PlayMontageAndWaitForEvent called on invalid AbilitySystemComponent"));
|
|||
|
}
|
|||
|
//播放失败处理
|
|||
|
if (!bPlayedMontage)
|
|||
|
{
|
|||
|
ABILITY_LOG(Warning, TEXT("URPGAbilityTask_PlayMontageAndWaitForEvent called in Ability %s failed to play montage %s; Task Instance Name %s."), *Ability->GetName(), *GetNameSafe(MontageToPlay),*InstanceName.ToString());
|
|||
|
if (ShouldBroadcastAbilityTaskDelegates())
|
|||
|
{
|
|||
|
OnCancelled.Broadcast(FGameplayTag(), FGameplayEventData());
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
SetWaitingOnAvatar();
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
## ExternalCancel()
|
|||
|
```
|
|||
|
check(AbilitySystemComponent);
|
|||
|
OnAbilityCancelled();
|
|||
|
Super::ExternalCancel();
|
|||
|
```
|
|||
|
OnAbilityCancelled的代码
|
|||
|
```
|
|||
|
if (StopPlayingMontage())
|
|||
|
{
|
|||
|
// Let the BP handle the interrupt as well
|
|||
|
if (ShouldBroadcastAbilityTaskDelegates())
|
|||
|
{
|
|||
|
OnCancelled.Broadcast(FGameplayTag(), FGameplayEventData());
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
## OnDestroy()
|
|||
|
```
|
|||
|
void URPGAbilityTask_PlayMontageAndWaitForEvent::OnDestroy(bool AbilityEnded)
|
|||
|
{
|
|||
|
// Note: Clearing montage end delegate isn't necessary since its not a multicast and will be cleared when the next montage plays.
|
|||
|
// (If we are destroyed, it will detect this and not do anything)
|
|||
|
|
|||
|
// This delegate, however, should be cleared as it is a multicast
|
|||
|
if (Ability)
|
|||
|
{
|
|||
|
Ability->OnGameplayAbilityCancelled.Remove(CancelledHandle);
|
|||
|
if (AbilityEnded && bStopWhenAbilityEnds)
|
|||
|
{
|
|||
|
//停止播放Montage
|
|||
|
StopPlayingMontage();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
URPGAbilitySystemComponent* RPGAbilitySystemComponent = GetTargetASC();
|
|||
|
if (RPGAbilitySystemComponent)
|
|||
|
{
|
|||
|
//移除事件绑定
|
|||
|
RPGAbilitySystemComponent->RemoveGameplayEventTagContainerDelegate(EventTags, EventHandle);
|
|||
|
}
|
|||
|
//这句必须放在最后
|
|||
|
Super::OnDestroy(AbilityEnded);
|
|||
|
}
|
|||
|
```
|
|||
|
## PlayMontageAndWaitForEvent
|
|||
|
PlayMontageAndWaitForEvent是Tasks的主体函数。
|
|||
|
```
|
|||
|
URPGAbilityTask_PlayMontageAndWaitForEvent* URPGAbilityTask_PlayMontageAndWaitForEvent::PlayMontageAndWaitForEvent(UGameplayAbility* OwningAbility,
|
|||
|
FName TaskInstanceName, UAnimMontage* MontageToPlay, FGameplayTagContainer EventTags, float Rate, FName StartSection, bool bStopWhenAbilityEnds, float AnimRootMotionTranslationScale)
|
|||
|
{
|
|||
|
//用于缩放GAS tasks变量的工具函数,此为非shipping功能,用于交互调试。
|
|||
|
UAbilitySystemGlobals::NonShipping_ApplyGlobalAbilityScaler_Rate(Rate);
|
|||
|
|
|||
|
//使用NewAbilityTask来创建Tasks,并且设置各个变量。
|
|||
|
URPGAbilityTask_PlayMontageAndWaitForEvent* MyObj = NewAbilityTask<URPGAbilityTask_PlayMontageAndWaitForEvent>(OwningAbility, TaskInstanceName);
|
|||
|
MyObj->MontageToPlay = MontageToPlay;
|
|||
|
MyObj->EventTags = EventTags;
|
|||
|
MyObj->Rate = Rate;
|
|||
|
MyObj->StartSection = StartSection;
|
|||
|
MyObj->AnimRootMotionTranslationScale = AnimRootMotionTranslationScale;
|
|||
|
MyObj->bStopWhenAbilityEnds = bStopWhenAbilityEnds;
|
|||
|
|
|||
|
return MyObj;
|
|||
|
}
|
|||
|
```
|