【Unreal Engine】Gameplay Ability System入門:入れるべきか判断する

作成: 2026-07-21

UEのGAS(Gameplay Ability System)を、導入する価値があるかを判断できるところまで解説。5つの登場人物、AttributeとGameplay Effect、CostとCooldownの仕組み、Gameplay Tagによる発動制限、そしてC++必須という導入コストと「入れない判断」まで。

スキルが3個のうちは、クールダウンもコストも自分で書けます。bCanUseFireballSet Timer で十分です。ところがスキルが15個になり、「毒状態だと詠唱できない」「バフ中は消費MPが半分」「スタン中は全部止まる」といった条件が絡み始めると、フラグの組み合わせが手に負えなくなります。

UEには、この領域を丸ごと引き受ける Gameplay Ability System(GAS) があります。強力ですが、導入コストも相応にかかります。この記事のゴールは、GASを完全に使いこなすことではありません。 自作のスキルシステムで足りるのか、GASを入れるべきなのかを、自分で判断できるようになる ことです。

先に前提を1つ。 GASの導入にはC++が必要です。 Blueprintだけでは完結しません。この記事は BlueprintからC++への移行入門 を終えた人を想定しています。

左に自作のフラグが増えて絡み合う様子、右にGASの5つの部品が整然と並ぶ様子を対比した図とソフトブルーのクレイ人形

この記事でわかること

  • GASが引き受けてくれる仕事の範囲
  • 5つの登場人物(ASC / Ability / Effect / Attribute Set / Tag)
  • AttributeGameplay Effect の3つの持続タイプ
  • CostCooldown が「Effectとして表現される」仕組み
  • Gameplay Tagで「今は撃てない」を表す方法
  • 実践: MP20消費・クールダウン5秒のファイアボール
  • 入れない判断 の基準

Sponsored

GASが引き受ける仕事

GASは「スキルを作る機能」ではありません。スキルの周りにある 面倒な共通処理 をまとめて引き受ける仕組みです。

自作でスキルを1個作るとき、実際に書くことを並べてみます。

やること自作だと
発動できるか判定bCanUse などのフラグを自分で管理
MPを消費する変数を減らす。足りるかの事前チェックも自分で
クールダウンを回すTimerを1つ持ち、残り時間をUIへ伝える
効果を適用する相手のHPを減らす。防御力の計算もここ
バフ・デバフを重ねる重複したときの扱いを毎回考える
状態異常で止めるスキルごとに「スタン中か」を確認

スキルが3個なら、この表を3回書くだけです。15個になると、6列 × 15行の管理になります。しかも列同士が干渉します。

スキルが増えるほどフラグとTimerが増えて絡み合う自作の図と、共通処理をGASが引き受けてAbilityが並列に並ぶ図の対比

GASは、この表の 左の列を全部エンジン側に持っていきます 。あなたが書くのは「このスキルは何をするか」だけになります。

代わりに払うのは、登場人物を5つ覚えるコストと、C++で最低限の土台を組むコストです。 この交換が割に合うかどうかが、この記事の判断ポイント です。

5つの登場人物

GASは部品の名前が多くて、そこで挫折しがちです。ただし中心になるのは5つだけです。

Ability System Componentを中心に、Gameplay Ability・Gameplay Effect・Attribute Set・Gameplay Tagがぶら下がる関係図
登場人物役割例えると
Ability System Component(ASC)全部の窓口。Actorに1つ付ける受付カウンター
Gameplay Ability1つのスキルの中身「ファイアボールを撃つ」手順書
Gameplay EffectAttributeを変える指示「HPを30減らす」伝票
Attribute SetHP・MPなどの数値の入れ物ステータス表
Gameplay Tag状態や種類を表す文字列の階層付箋(State.Stunned

流れで見ると単純です。プレイヤーがボタンを押す → ASCに「このAbilityを発動して」と頼む → ASCがコストとクールダウンとタグを確認 → 通れば Ability が走る → Ability が Gameplay Effect を相手に適用する → Effect が Attribute を変える。

ゲーム中のAttributeの増減は、原則としてGameplay Effect経由で書きます。 ダメージも回復もバフも、直接Setせずに伝票(GE)を切る。ここがGASのいちばんの流儀で、慣れるまでは遠回りに感じるところです(初期値の設定など、管理的な代入まで禁止というわけではありません)。

Gameplay Tagについては Gameplay Tagsでタグベースの柔軟な設計 で先に扱っています。GASはこのタグを全面的に使うので、先にそちらを読んでおくと理解が速くなります。

AttributeとGameplay Effect

Attribute は、GASが管理する数値です。HP、最大HP、MP、攻撃力、移動速度。ゲームのステータスと呼ばれるものは、だいたいAttributeになります。

Attributeは float ですが、ただの変数ではありません。 Base値とCurrent値の2つ を持ちます。

  • Base値:基準になる値。ダメージや回復のように 永続的に変わる 増減は、こちらが動く
  • Current値:Base値に、いま効いているバフ・デバフを乗せた結果。 実際に使われる値

攻撃力のBaseが10で、+5のバフがかかっていればCurrentは15。バフが切れると、何もしなくてもCurrentは10へ戻ります。 「バフを外したら元に戻す」処理を自分で書かなくていい のは、この構造のおかげです。

Base値10に対してバフ+5が乗ってCurrent値15になり、バフが切れると自動で10へ戻る様子を時間軸で示した図

Attributeを変えるのが Gameplay Effect(GE) です。GEには持続の仕方が3種類あります。

持続タイプ挙動使う場面
Instant即座に Base値 を変えて消えるダメージ、回復、MP消費
Has Duration一定時間 Current値 を変え、切れると戻る5秒の攻撃力アップ、移動速度低下
Infinite明示的に外すまで Current値 を変え続ける装備の補正、常時オーラ

ここは間違えやすいので、もう一度。 ダメージはInstant(Baseを削る)、バフはDurationかInfinite(Currentを動かす) 。攻撃ダメージをDurationで作ると、時間が経つとHPが勝手に戻ります。

なお、Duration/Infinite に Period(周期) を設定すると話が変わります。周期ごとにInstantと同じ扱いで実行されるので、 Base値が削れて戻りません 。毒や継続回復はこちらで作ります。「時間で戻るのがDuration」は、周期を付けていない場合の話だと覚えておいてください。

Gameplay Effectのアセットは、GameplayEffect を親にしたBlueprintとして作ります。グラフは書きません。 Class Defaultsの設定だけで完結する 、データに近いアセットです(→ Data Assetによるデータ駆動設計 と同じ発想です)。

Sponsored

CostとCooldownもEffectで表す

GASを触っていて「なるほど」となるのが、ここです。

MP消費もクールダウンも、中身はただのGameplay Effectです。 Abilityに専用の指定欄はありますが、そこに入れるのは普通のGEアセットで、特別な仕組みは何もありません。

Cost用のInstant EffectがMPを減らし、Cooldown用のDuration Effectがタグを付与して5秒後に消える様子を並�べた図
  • CostInstant のGEで、Mana を -20 する。Abilityの Cost Gameplay Effect Class に指定します
  • CooldownHas Duration(5秒)のGEで、Cooldown.Fireball という タグを付与するだけ 。Abilityの Cooldown Gameplay Effect Class に指定します

クールダウンのGEは、数値を1つも変えません。 「5秒間このタグを付ける」だけ です。GASは発動前に、そのタグが付いていないかを見ます。付いていれば発動を弾く。それだけの仕組みで、クールダウンが成立します。

この2つが適用されるのは、Abilityの中で Commit Ability を呼んだ瞬間です。発動を試みた時点では「払えるか」「クールダウン中でないか」を 確認するだけ で、実際にMPが減るのはCommitのときです。ここは実践で必ず引っかかるところなので、先に頭に入れておいてください。

うれしいのは、この構造がそのままUIに使える点です。ASCに問い合わせれば クールダウンの残り時間 が取れるので、スキルアイコンの暗転や数字表示を、Ability側に何も足さずに作れます(表示側の組み方は UMGでHUDを作る)。

Costのほうも同様で、GASは発動前に「このGEを適用できるか(=MPが足りるか)」を先に確認します。 足りないなら発動そのものが起きない ので、「MPが足りないのにエフェクトだけ出た」といった中途半端な状態になりません。

Gameplay Tagで「今は撃てない」を表す

自作でスキル管理が破綻する最大の原因は、条件フラグです。bIsStunnedbIsSilencedbIsCastingbIsDead。スキルを足すたびに、全部のフラグを確認するコードが増えていきます。

GASでは、これを タグの有無 で表します。

キャラクターにState.Stunnedタグが付いている間、Ability発動がブロックされる様子を示した図

Abilityの設定に、次のようなタグ欄があります。

設定項目意味
Ability TagsこのAbility自身を表すタグ(Ability.Fireball
Activation Blocked Tags持っていると 発動できない タグ(State.Stunned
Activation Required Tags持っていないと 発動できない タグ(Weapon.Equipped
Activation Owned Tags発動中、自分に 付き続ける タグ(State.Casting

スタンさせたいときは、State.Stunned タグを付与するGEを相手に適用するだけです。 スキル側のコードは1行も触りません。 新しく作ったスキルも、Activation Blocked TagsState.Stunned を入れておけば、自動的にスタンで止まります。

さらに、タグは階層です。State.StunnedState.Frozen を両方ブロックしたいなら、State を親に持たせて State でまとめて弾く こともできます。フラグの列挙が、木構造の1点に置き換わります。

導入コストの現実

ここまで読むと入れたくなりますが、導入の実際を先に見ておきます。

1. プラグインを有効化する。 Edit → PluginsGameplay Abilities を検索して有効化し、エディタを再起動します。

2. C++が必要になる。 Attribute Setは C++でクラスを定義する必要があります 。Blueprintだけでは作れません。あわせて、プロジェクトの Build.cs に依存モジュールを足します。

// MyProject.Build.cs
PublicDependencyModuleNames.AddRange(new string[] {
    "Core", "CoreUObject", "Engine", "InputCore",
    "GameplayAbilities", "GameplayTags", "GameplayTasks"   // この3つを追加
});

Attribute Setは、こうした形になります。

// MyAttributeSet.h
#pragma once
#include "AttributeSet.h"
#include "AbilitySystemComponent.h"
#include "MyAttributeSet.generated.h"

// 4つのアクセサをまとめて生やす定番マクロ
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
    GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
    GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
    GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
    GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)

UCLASS()
class MYPROJECT_API UMyAttributeSet : public UAttributeSet
{
    GENERATED_BODY()

public:
    // Attributeは float ではなく FGameplayAttributeData で持つ
    UPROPERTY(BlueprintReadOnly, Category = "Attributes")
    FGameplayAttributeData Health;
    ATTRIBUTE_ACCESSORS(UMyAttributeSet, Health)

    UPROPERTY(BlueprintReadOnly, Category = "Attributes")
    FGameplayAttributeData Mana;
    ATTRIBUTE_ACCESSORS(UMyAttributeSet, Mana)
};

3. ASCを持たせ、Attribute Setを登録し、初期化する。 ここが3段構えになっているのが、GASの入口でいちばん詰まる場所です。

  • キャラクターに Ability System Component を付ける
  • 作った Attribute Set を、そのASCに登録する 。クラスを書いただけでは中身が存在しません。C++でサブオブジェクトとして生成するか、ASCの詳細パネルにある Default Starting Data へ追加します
  • InitAbilityActorInfo で「所有者は誰か、実際に動くActorはどれか」を教える。 これはBlueprintノードとして公開されていないので、C++から呼びます

この3段は、シングルプレイのCharacterなら次の10行程度で足ります。ASCとAttribute Setをコンストラクタでサブオブジェクトとして生成すると、同じActorに乗ったAttribute SetはそのASCから見つけられます。

// MyCharacter.h(抜粋)
UPROPERTY() UAbilitySystemComponent* ASC;
UPROPERTY() UMyAttributeSet* Attributes;

// MyCharacter.cpp
AMyCharacter::AMyCharacter()
{
    ASC        = CreateDefaultSubobject<UAbilitySystemComponent>(TEXT("ASC"));
    Attributes = CreateDefaultSubobject<UMyAttributeSet>(TEXT("Attributes"));
}

void AMyCharacter::BeginPlay()
{
    Super::BeginPlay();
    ASC->InitAbilityActorInfo(this, this);   // 所有者, 実際に動くActor(ともに自分)
}

3つのどれが欠けても、症状は同じ「何も起きない」です。 Abilityが動かないときは、まずこの3点を上から確認する と決めておくと、迷いません。

Ability と Gameplay Effect のアセット自体は、Blueprintで作れます。 C++が要るのは土台の部分だけ で、日々のスキル追加はBlueprintで進められます。それでも、最初の1回はC++を通る必要があります。

4. 学習の踊り場が長い。 5つの登場人物を覚えても、Gameplay Effect Execution Calculation(攻撃力と防御力から最終ダメージを計算する仕組み)や Gameplay Cue(演出の同期)まで含めると、まだ先があります。

実践:ファイアボールを1本通す

判断材料をそろえるために、いちばん小さい形で1本通します。

ARPGの攻撃スキル、ローグライクのアイテム効果、対戦アクションの必殺技。 「コストを払い、クールダウンがあり、相手に効果を与える」 という形は、ジャンルを問わず同じです。ここではその最小形を作ります。

作るのは、 MPを20消費し、5秒のクールダウンで、相手のHPを30減らすファイアボール です。

動かすとこうなります。MPが100の状態でボタンを押すと、MPが80になって弾が飛び、当たった相手のHPが30減る。すぐもう一度押しても、5秒経つまで何も起きません。MPが20を切ると、同じく何も起きません。 「押したのに出ない」が、コードを書かずに成立します。

MP100からファイアボールを撃つとMP80になり、5秒間は再発動がブロックされ、MP20未満でも発動しない様子を時間軸で並べた図

再現条件

項目
プラグインGameplay Abilities を有効化してエディタ再起動
C++クラス上記の UMyAttributeSetHealth / Mana
ASCプレイヤーとターゲットの 両方 に Ability System Component を追加し、UMyAttributeSet を登録、InitAbilityActorInfo を呼ぶ
初期値Health = 100Mana = 100
Gameplay TagAbility.Fireball / Cooldown.Fireball / State.Stunned を登録
ターゲット側Overlapを拾えるCollisionを持つActor(Generate Overlap Eventsを有効に)
想定シングルプレイ 。マルチプレイにはAttributeのReplication設定などが別途要ります

Attributeの初期値は、Instant のGEを BeginPlay で自分に適用して入れるのが簡単です。Modifierを Override = 100 にしておくと、二度適用しても200にならないので安全です。

数値の変化は目に見えないので、HPとMPを Print String で毎回出す か、簡単なUIを1つ置いておいてください。確認できないと、動いているのか判断できません。

ステップ1:3つのGameplay Effectを作る

コンテンツブラウザで右クリック → Blueprint Class → 親クラスに GameplayEffect を選び、3つ作ります。どれもグラフは書かず、Class Defaultsだけを設定します。

アセットDuration Policy設定
GE_Cost_FireballInstantModifier:Mana / Add / -20
GE_Cooldown_FireballHas DurationDuration = 5.0、付与タグに Cooldown.Fireball
GE_Damage_FireballInstantModifier:Health / Add / -30

GE_Cooldown_Fireball の「付与タグ」は、効果が続くあいだ対象に付くタグの欄です。 UE5.3でここのUIが変わりました。

  • UE5.3以降GameplayEffect ComponentsGrant Tags to Target Actor を追加し、その Add TagsCooldown.Fireball を入れる
  • それ以前:Class Defaultsの Granted Tags に直接書く

場所が変わっただけで、意味は同じ です。ネットの解説記事がどちらの世代のものか分からなくなったら、この違いを疑ってください。

ステップ2:Abilityを作る

Blueprint Class → 親クラスに GameplayAbility を選び、GA_Fireball として作成します。Class Defaultsで次を設定します。

設定項目
Ability Tags(UE5.8では Asset TagsAbility.Fireball
Cost Gameplay Effect ClassGE_Cost_Fireball
Cooldown Gameplay Effect ClassGE_Cooldown_Fireball
Activation Blocked TagsState.Stunned
Instancing PolicyInstanced Per Actor

Instancing PolicyInstanced Per Actor にしておくと、Actorごとに1つのインスタンスが使い回されます。Ability内で変数を持ったりイベントを待ったりできて、無駄なインスタンスも増えません。1発ずつ独立した状態を持たせたいなら Instanced Per Execution もありますが、この単発スキルならPer Actorが素直です。

グラフはこうなります。

GA_Fireball(イベントグラフ)

Event ActivateAbility
  → Commit Ability                        // ★ここでMPが減り、クールダウンが始まる
      (成功)
      → Get Avatar Actor From Actor Info  // 撃つ本人
      → Make Outgoing Gameplay Effect Spec(GE_Damage_Fireball, Level = 1)
      → Spawn Actor from Class(BP_Fireball、本人の前方 100uu)
           生成した弾の変数「DamageSpec」に、上で作ったSpecを渡す
      → End Ability
      (失敗)
      → End Ability                        // 何も起きずに閉じる
GA_FireballのイベントグラフでEvent ActivateAbilityからCommit Abilityを呼び、成功時はMake Outgoing SpecとSpawn Actorを経てEnd Ability、失敗時はそのままEnd Abilityへ分岐するノードグラフ

Commit Ability を書き忘れると、MPは減らず、クールダウンも始まりません。 発動時のチェックは「払えるか」を見るだけで、実際に支払うのはCommitの瞬間です。 1発目は撃てるのに連打できてしまう ときは、まずここを疑ってください。Commitは失敗することもあるので、戻り値で分岐して、失敗時は弾を出さずに閉じます。

ダメージのSpec(伝票)を 撃つ側のAbilityで作って弾に渡している のも要点です。弾の側で作ると、「誰が撃ったか」の情報が弾自身になってしまい、あとから攻撃力を参照したりキル判定を足したりするときに破綻します。 伝票は発行元で作る。

そして End Ability を忘れないでください。 Abilityは明示的に終了させないと動いたままになり、Instanced Per Actor では次の発動が拒否されます。「1回撃ったら二度と撃てない」の原因はほぼこれです。

ステップ3:発動につなぐ

プレイヤーのキャラクターBlueprintで、Abilityを登録してから、入力で発動します。

BP_MyCharacter(イベントグラフ)

Event BeginPlay
  → Ability System Component → Give Ability(Ability Class = GA_Fireball)

IA_Fire(Enhanced Inputの Started)
  → Ability System Component → Try Activate Ability by Class(GA_Fireball)

Give Ability はサーバー側(シングルプレイなら通常のBeginPlayでよい)で1回だけ呼びます。以降は Try Activate Ability by Class を叩くだけです。入力の組み方は Enhanced Input System入門 を参照してください。

弾(BP_Fireball)は、Collision(Generate Overlap Events 有効)と Projectile Movement を持つActorです。撃った本人に当たらないよう、自分の所有者は無視するようにしておきます。当たったら、Abilityから受け取ったSpecを相手のASCへ適用します。

BP_Fireball(イベントグラフ)
  変数:DamageSpec(Gameplay Effect Spec Handle)— Abilityから渡される

On Component Begin Overlap
  → Other Actor から Ability System Component を取得
  → (有効なら)Apply Gameplay Effect Spec to Self(Target = 相手のASC, Spec = DamageSpec)
  → Destroy Actor

ノード名の to Self は「Targetピンに指定したASC自身へ適用する」という意味です。相手のASCをTargetに渡しているので、ダメージが入るのは相手です。

確かめる

Playして、ファイアボールを撃ちます。

  • MPが 100 → 80 に減る
  • すぐもう一度押しても 何も起きない 。5秒経つと撃てる
  • 5発撃つとMPが0になり、 それ以上は押しても出ない
  • 当たった相手のHPが 100 → 70 になる

タグの効き目も確かめられます。確認の最後に、自分へ State.Stunned を付与するGE(Has Duration 3秒)を適用してから撃ってみてください。 3秒間だけ発動が黙って弾かれますGA_Fireball のコードは1行も触っていないのに、Activation Blocked Tags に入れた1行だけで止まります。これがタグ方式の効き目です。

想定どおりに動かないときの切り分けです。

  • 弾は出るのにMPが減らず、連打できるCommit Ability が抜けています。いちばん多い症状です
  • 何も起きない(Event ActivateAbility すら来ない) → 土台の3点を上から確認します。ASCがある/Attribute Setが登録されている/InitAbilityActorInfo を呼んでいる。加えて Give Ability が実行されているか、State.Stunned が付いたままでないかも見てください
  • 1回だけ撃てて、以降うんともすんともEnd Ability を呼んでいません
  • クールダウン中でも撃てるCooldown Gameplay Effect Class が空か、タグの付与設定(Grant Tags to Target Actor / Granted Tags)が入っていません
  • 相手のHPが減らない → 相手側にASCとAttribute Setが無いか、弾がOverlapを拾えていません

ポイントは2つです。

  • 同じ挙動は自作でも書ける: いま作ったものは、Mana 変数と Set Timer があれば1時間で書けます。GASの価値は、この1本を作れることではなく、 2本目以降がほぼ設定だけで済む ことです。アイスランスを作るなら、GEを2つコピーして数字を変え、Abilityを1つ作るだけ。判定コードは1行も増えません
  • 効いてくるのは「条件が増えたとき」: スタン、沈黙、詠唱中、装備条件。自作ならスキル15個 × 条件5種で75通りの確認が要ります。GASはタグ欄に1行足すだけで、既存のスキルにも新しいスキルにも同じ制限がかかります(→ Gameplay Tagsでタグベースの柔軟な設計

逆に言えば、 スキルが5個で条件がほぼ無いなら、この構造は重すぎます。 そのときはEnumとTimerの自作で十分です(→ EnumとSwitchでステートを管理する体力とダメージをApply Damageで作る)。

Sponsored

おまけ:先に知っておくと良いこと

ASCをどこに付けるかは、あとから変えにくい選択です。 シングルプレイなら Character に付けるのが素直です。マルチプレイで、死んでリスポーンしてもバフやステータスを保ちたいなら PlayerState に付けるのが定番です。GASは元々マルチプレイ前提で作られているので、ネットワークを考えるならこの判断を先にしてください(→ マルチプレイの基礎:レプリケーションGame Frameworkの理解)。

演出はGameplay Cueに寄せられます。 「ダメージを受けたら赤く光って音を鳴らす」といった見た目の処理を、タグ経由で呼び出す仕組みです。ロジックと演出を分けられるので、GASを本格的に使うなら覚える価値があります。ただし最初の1本では要りません。

HPの上限クランプは自分で書きます。 GASに自動のクランプはありません。C++で UAttributeSet のコールバックをオーバーライドして実装します。Instant GEでBase値が動くHPなら PostGameplayEffectExecute で結果を丸めるのが分かりやすく、バフ込みのCurrent値を抑えたいなら PreAttributeChange です。「回復しすぎて最大HPを超える」は、GASを入れただけでは防げません。

Lyraは参考になりますが、最初の教材には重すぎます。 Epic公式のサンプル Lyra Starter Game はGASの実践例として非常に良くできていますが、その分抽象化が厚く、初見で全体像をつかむのは大変です。まず自分の手で最小構成を1本通してから読むと、格段に理解しやすくなります。

まとめ

GASは、スキルの周辺にある共通処理をエンジンへ預ける仕組みです。

判断状況
入れなくてよいスキルが5個前後。状態異常がほぼ無い。C++を避けたい
入れると楽になるスキルが10個を超える。バフ・デバフが重なる。状態異常で制限が要る
ほぼ必須大量のスキルとアイテム効果があり、マルチプレイ対応もする

判断の軸は、スキルの数そのものではありません。 「発動できるか」の条件が、スキル同士で共有され始めたかどうか です。共有され始めた瞬間から、自作のフラグ管理は指数関数的に苦しくなり、GASのタグ方式が効いてきます。

そしてもう1つ。 迷っているなら、まだ入れなくていい というのが実務的な結論です。GASは後から入れられます。自作で作ったスキルが5個を超え、条件の確認コードが同じ形で何度も出てきたら、そのときが移行の合図です。

あなたのゲームのスキルは、いま何個で、そのうち何個が「他の状態のせいで撃てない」条件を持っているでしょうか。その2つの数字が、答えを出してくれます。

さらに学ぶために