2023-06-29 11:55:02 +08:00

167 lines
6.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## UAbilityTask
UAbilityTask继承自UGameplayTaskUGameplayTask可以用来写一些行为树中的一些节点可以用来实现一些异步功能。比如播放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;
}
```