【UE】特定のGameplayTagが追加（削除）されるまで待機するBehaviorTreeTask(c++)

# 概要
敵の行動をGameplayAbilityで作成する時に、BehaviorTree上で特定のTagが追加されるまで次のタスクを実行してほしくない時があったので作成しました。
## 特定のタグが追加されるまで待機するBTT  
.h
~~~c++
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "BehaviorTree/Tasks/BTTask_BlackboardBase.h"
#include "AbilitySystemInterface.h"
#include "BTT_WaitAddGameplayTag.generated.h"

/**
 * 
 */
UCLASS()
class UBTT_WaitAddGameplayTag : public UBTTask_BlackboardBase
{
	GENERATED_BODY()
	
public:
	explicit UBTT_WaitAddGameplayTag(FObjectInitializer const& ObjectInitializer);
	virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
	virtual void TickTask(
		UBehaviorTreeComponent& OwnerComp,
		uint8* NodeMemory,
		float DeltaSeconds
	) override;
private:
	UPROPERTY(EditAnywhere, Category = "Param", meta = (AllowprivateAccese = "true"))
	FGameplayTagContainer WaitTag;
	UPROPERTY(EditAnywhere, Category = "Param", meta = (AllowprivateAccese = "true"))
	bool IsAll; // trueの場合全てのタグが追加されるまで待機。falseの場合いずれかのタグが追加されるまで待機。
};
~~~
.cpp
~~~c++
// Fill out your copyright notice in the Description page of Project Settings.


#include "Character/Enemy/BTT_WaitAddGameplayTag.h"
#include "Character/GAS_Character.h"
#include "AbilitySystemComponent.h"
#include "AIController.h"

UBTT_WaitAddGameplayTag::UBTT_WaitAddGameplayTag(FObjectInitializer const& ObjectInitializer)
{
	NodeName = "WaitAddGameplayTag";
	bNotifyTick = true;
}

EBTNodeResult::Type UBTT_WaitAddGameplayTag::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
	return EBTNodeResult::InProgress;
}

void UBTT_WaitAddGameplayTag::TickTask(
	UBehaviorTreeComponent& OwnerComp, 
	uint8* NodeMemory, 
	float DeltaSeconds)
{
	if (AGAS_Character* character = Cast<AGAS_Character>(OwnerComp.GetAIOwner()->GetPawn()))
	{
		if (IsAll)
		{
			if (character->GetAbilitySystemComponent()->HasAllMatchingGameplayTags(WaitTag))
			{
				FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
			}
		}
		else
		{
			if (character->GetAbilitySystemComponent()->HasAnyMatchingGameplayTags(WaitTag))
			{
				FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
			}
		}
	}
	else
	{
		FinishLatentTask(OwnerComp, EBTNodeResult::Failed);
	}
}
~~~
　  

## 特定のタグが削除されるまで待機するBTT  
.h
~~~c++
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "BehaviorTree/Tasks/BTTask_BlackboardBase.h"
#include "BTT_WaitRemoveGameplayTag.generated.h"

/**
 * 
 */
UCLASS()
class UBTT_WaitRemoveGameplayTag : public UBTTask_BlackboardBase
{
	GENERATED_BODY()
	
public:
	explicit UBTT_WaitRemoveGameplayTag(FObjectInitializer const& ObjectInitializer);
	virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
	virtual void TickTask(
		UBehaviorTreeComponent& OwnerComp,
		uint8* NodeMemory,
		float DeltaSeconds
	) override;
private:
	UPROPERTY(EditAnywhere, Category = "Param", meta = (AllowprivateAccese = "true"))
	FGameplayTagContainer WaitTag;
	UPROPERTY(EditAnywhere, Category = "Param", meta = (AllowprivateAccese = "true"))
	bool IsAll; // 追加の条件と同じ
};
~~~
.cpp
~~~c++
// Fill out your copyright notice in the Description page of Project Settings.


#include "Character/Enemy/BTT_WaitRemoveGameplayTag.h"
#include "Character/GAS_Character.h"
#include "AbilitySystemComponent.h"
#include "AIController.h"

UBTT_WaitRemoveGameplayTag::UBTT_WaitRemoveGameplayTag(FObjectInitializer const& ObjectInitializer)
{
	NodeName = "WaitRemoveGameplayTag";
	bNotifyTick = true;
}

EBTNodeResult::Type UBTT_WaitRemoveGameplayTag::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
	return EBTNodeResult::InProgress;
}

void UBTT_WaitRemoveGameplayTag::TickTask(
	UBehaviorTreeComponent& OwnerComp, 
	uint8* NodeMemory, 
	float DeltaSeconds)
{
	if (AGAS_Character* character = Cast<AGAS_Character>(OwnerComp.GetAIOwner()->GetPawn()))
	{
		if (IsAll)
		{
			if (!character->GetAbilitySystemComponent()->HasAnyMatchingGameplayTags(WaitTag))
			{
				FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
			}
		}
		else
		{
			if (!character->GetAbilitySystemComponent()->HasAllMatchingGameplayTags(WaitTag))
			{
				FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
			}
		}
	}
	else
	{
		FinishLatentTask(OwnerComp, EBTNodeResult::Failed);
	}
}
~~~
## 補足
**AGAS_Character**は**IAbilitySystemInterface**を継承したクラスで、**UAbilitySystemComponent**を持ちます。  
## 参考にさせていただいたサイト
[UE4 GameplayAbility Pluginについてのメモ](https://qiita.com/unknown_ds/items/6d4438646827bbe08f4a#hasmatchinggameplaytag)
[GameplayAbilitiesの使い方(セットアップ編)](https://okawari-hakumai.hatenablog.com/entry/2018/07/22/165242)