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;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 |