概要
UnrealEngine5 の GameplayAbilitySystem(GAS) での BlockTagについてのメモ。
Block Abilities with Tag
を使うと指定タグを持つアビリティの発動をブロックできますが、アビリティ動作途中までブロックしたいようなケースがあったのでメモ書きです。
更新履歴
日付 | 内容 |
---|---|
2023/12/07 | 初版 |
2024/07/09 | アビリティ失敗時のタグ情報について追記 |
参考
以下の記事を参考にいたしました、ありがとうございます。
UE5公式:ゲームプレイアビリティシステム
UE公式:UAbilitySystemComponent::BlockAbilitiesWithTags
【UE5】GASと対話する【備忘録】
関連する過去記事
UE4 GameplayAbility Pluginについてのメモ
環境
Windows10
Visual Studio 2022
UnrealEngine 5.2.1
関連ソース
"Engine\Plugins\Runtime\GameplayAbilities\Source\GameplayAbilities\Public\AbilitySystemComponent.h"
"Engine\Plugins\Runtime\GameplayAbilities\Source\GameplayAbilities\Private\AbilitySystemComponent_Abilities.cpp"
GASのブロックタグについて
Block Abilities with Tag の動作
アビリティクラスの設定の Block Abilities with Tag
にタグを設定すると、その設定されたタグを持つアビリティの起動をブロックすることができます。
上記の設定だと、Ability.Skill.Test1
を持つアビリティが動作している間は Ability.Skill.Test2
が発動しないようにブロックしています。
Activation Block Tags の動作
こちらも設定したタグを持つアビリティの起動をブロックします。
Block Abilities with Tag
の違いは該当のタグを持つアビリティをブロックする以外にもアクターが持っている場合にブロックされるようです、あとは失敗時のコールバック時に失敗理由判定タグがないなど細かい違いがあるようです。
// アビリティ発動失敗時コールバック
void AMyCharacter::OnAbilityFailed(const UGameplayAbility* _Ability, const FGameplayTagContainer& _GameplayTags)
{
//# アビリティ発動失敗時コールバックに原因のゲームタグを得るには
//# DefaultGame.ini に以下の登録と、UAbilitySystemGlobals::Get().InitGlobalData(); が必要(アセットマネージャ初期化でやるのがおすすめ)
//#
//# [/Script/GameplayAbilities.AbilitySystemGlobals]
//# ActivateFailCostName="Ability.Fail.Cost"
//# ActivateFailCooldownName="Ability.Fail.Cooldown"
//# ActivateFailTagsBlockedName="Ability.Fail.Block"
//# ActivateFailTagsMissingName="Ability.Fail.RequiredTags"
if( _GameplayTags.HasTag( FGameplayTag::RequestGameplayTag(FName("Ability.Fail.Cooldown"))) ){
// クールダウン中
}
if( _GameplayTags.HasTag( FGameplayTag::RequestGameplayTag(FName("Ability.Fail.Cost"))) ){
// コスト不足
}
if( _GameplayTags.HasTag( FGameplayTag::RequestGameplayTag(FName("Ability.Fail.Block"))) ){
// 他のアビリティにブロックされた
// `Block Abilities with Tag`タグでブロックされた場合
}
if( _GameplayTags.HasTag( FGameplayTag::RequestGameplayTag(FName("Ability.Fail.RequiredTags"))) ){
// 発動に必要なタグがない
}
}
アビリティ実行途中でブロックをやめる
上記ブロックタグを使うと該当アビリティ動作中は指定のアビリティをブロックすることができますが、途中までブロックして解除したいというようなケースもあり得ます。
このような場合、GASのプロパティで Block Abilities with Tag
を設定した上で AbilitySystemComponent
クラスの UnBlockAbilitiesWithTags
で解除。もしくはブロックしたいタイミングで BlockAbilitiesWithTags
でブロックということもできるようです。
内部的にはBlockedAbilityTags
でカウントしているのでブロック/アンブロックの呼び出し回数に注意が必要です。GASのインスタンスポリシーがEGameplayAbilityInstancingPolicy::InstancedPerActor
の場合、アビリティが終了しても呼び出しカウンタが継続するため不具合となることが考えられます。
/** 特定のアビリティタグのブロックまたはブロックのキャンセル */
void BlockAbilitiesWithTags(const FGameplayTagContainer& Tags);
void UnBlockAbilitiesWithTags(const FGameplayTagContainer& Tags);
protected:
/** これらのタグが付いているアビリティは発動できません */
FGameplayTagCountContainer BlockedAbilityTags;
BlockAbilitiesWithTags
UnBlockAbilitiesWithTags
は以下のように実装されています。カウント数を取得/設定するには BlockedAbilityTags
に対し、GetTagCount()
SetTagCount()
で可能です。
void UAbilitySystemComponent::BlockAbilitiesWithTags(const FGameplayTagContainer& Tags)
{
BlockedAbilityTags.UpdateTagCount(Tags, 1);
}
void UAbilitySystemComponent::UnBlockAbilitiesWithTags(const FGameplayTagContainer& Tags)
{
BlockedAbilityTags.UpdateTagCount(Tags, -1);
}
適用例
モンタージュに任意のイベントタグを入れて Play Montage Wait for Event
等で受け取って切り替える方法があります。
Play Montage Wait for Event
はデフォルトのプラグインには付属していません。
https://github.com/tranek/GASDocumentation を参考にしました。
アニメーション通知の処理は以下のような感じになるかと思います。
void UAnimNotify_EventTag::Notify(
USkeletalMeshComponent* MeshComp,
UAnimSequenceBase* Animation,
const FAnimNotifyEventReference& EventReference
)
{
AActor* _Actor = MeshComp->GetOwner();
ACharacter* _Chara = Cast<ACharacter>(_Actor);
if(_Chara){
// イベント呼び出し
FGameplayEventData _Payload;
UAbilitySystemBlueprintLibrary::SendGameplayEventToActor(_Actor, EventTag, _Payload);
}
}
その他
CanActivateAbility()で実行ブロック時の失敗情報付与
UGameplayAbility::CanActivateAbility()
で独自にアビリティを実行失敗にした場合、OptionalRelevantTags
に失敗原因タグをつけることでコールバックメソッドで受け取ることができます。
以下サンプルコード。
bool UMyGameplayAbility::CanActivateAbility(
const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo,
const FGameplayTagContainer* SourceTags,
const FGameplayTagContainer* TargetTags,
OUT FGameplayTagContainer* OptionalRelevantTags
) const
{
if (!Super::CanActivateAbility(Handle, ActorInfo, SourceTags, TargetTags, OptionalRelevantTags))
{
// 失敗コールバック用にタグ情報を付与する
OptionalRelevantTags->AddTag(FGameplayTag::RequestGameplayTag(FName("Ability.Fail.Other")));
return(false);
}
return(true);
}
// アビリティ発動失敗時コールバック
void AMyCharacter::OnAbilityFailed(const UGameplayAbility* _Ability, const FGameplayTagContainer& _GameplayTags)
{
if( _GameplayTags.HasTag( FGameplayTag::RequestGameplayTag(FName("Ability.Fail.Other"))) ){
// CanActivateAbility()でfalseが返ってきた
}
}
まとめ
BlockAbilitiesWithTags
UnBlockAbilitiesWithTags
はC++のみになっているため、BPで制御するにはアビリティコンポーネントを継承して使わないとならないようです。