スポンサーリンク
Unity C#・スクリプト実装

UnityでRPGスキルシステムを作る!クールダウン・キャンセル処理の実装設計

Unity C#・スクリプト実装

Unityでスキルを実装したものの、「クールダウン中なのにボタンを連打すると発動してしまう」「アニメーションの途中で次のスキルが割り込んできてしまう」といったトラブルに悩んでいませんか。

スキルの種類が増えてくると、条件分岐やフラグがどんどん複雑になり、どこから手をつけて直せばいいのか分からなくなってしまうことも多いですよね。

この記事では、Unityでスキルにクールダウンをつける方法と、連打による多重発動を防ぐキャンセル処理の実装方法を、コード例を交えながら解説していきます。


クールダウンとキャンセル処理は別物

スキルの実装でつまずきやすいポイントとして、まず整理しておきたいのが「クールダウン」と「キャンセル処理」の違いです。この2つ、なんとなく似たものだと思われがちなのですが、実は役割がまったく違います。

クールダウンは、スキルを使ってから次に使えるようになるまでの「待ち時間」を管理するものです。一方でキャンセル処理は、スキルが発動している最中に、別の入力が割り込んでこないようにする「重複実行の防止」のことを指します。

この違いを意識しないまま実装を進めてしまうと、こんな不具合が起きがちです。

  • クールダウンは正しく実装したのに、アニメーション再生中にボタンを連打すると同じスキルが何度も発動してしまう
  • 逆に、連打対策だけしていて、クールダウンの管理を忘れてしまい、待ち時間なしで使い放題になってしまう

つまり、クールダウンとキャンセル処理は「別々に実装する必要がある2つの仕組み」だと考えておくと、これから先の実装がぐっと整理しやすくなります。

enumで状態管理すればステートパターンになる?

スキルの状態を「Ready」「Casting」「Cooldown」のようにenum(列挙型)で分けて管理する方法は、この記事でもこの後紹介していきます。

ただ、ここで少し誤解しやすいのが、「enumで状態を分けて管理すること」と、設計手法として知られる「ステートパターン」は、実は同じものではないという点です。

enumとif文(またはswitch文)による分岐は、あくまで手軽に状態を管理するための書き方のひとつです。ステートパターンは、状態ごとの処理をそれぞれ別のクラスに切り出して管理する、もう一段階踏み込んだ設計手法にあたります。

スキルの数が少ないうちは、enumによる管理で十分対応できます。まずはこのレベル感で実装を進めてみて、後から必要に応じて設計を見直していく、という流れで問題ありません。




スキル数で実装方法を選ぶ基準

クールダウンとキャンセル処理を別々に実装する必要があることは分かったところで、次に気になるのが「どこまで作り込めばいいのか」という点だと思います。

これは実装するスキルの数や、演出の複雑さによって、目安が変わってきます。

  • スキルが3〜4個程度で、状態も「発動中」「クールダウン中」くらいのシンプルなもの → enumとUpdate文での分岐で十分対応できます
  • スキルが5個以上あり、演出やUIとの連動も細かく必要になる → 状態遷移をまとめて管理できるステートマシンの導入を検討する価値があります

なぜこの数を目安にしているかというと、スキルが増えるたびにif文やbool変数がどんどん積み重なっていき、どこでどの条件が効いているのか把握しづらくなっていくためです。最初のうちは問題なく動いていても、後から1つスキルを追加しただけで、思わぬ場所に不具合が出てしまう、ということが起こりやすくなります。

逆に言うと、スキルが少ないうちから無理に複雑な設計を取り入れる必要はありません。まずはシンプルな実装で動かしてみて、管理しきれなくなってきたタイミングで設計を見直す、という進め方で十分です。

状態遷移を使ったスキル管理そのものについては、以下の記事でより詳しく解説していますので、ステートマシンでの管理方法が気になる方はあわせて参考にしてみてください。

ここから先は、まずシンプルな実装として、クールダウンの具体的な作り方から見ていきましょう。




クールダウンの実装手順

それでは、実際にクールダウンを実装する手順を見ていきましょう。ここでは、特別なライブラリを使わない、いちばんシンプルな方法から紹介します。

基本の流れは、次の3ステップです。

  • クールダウン用の変数を用意する
  • スキルを使った瞬間に、必要な待ち時間をその変数にセットする
  • 毎フレーム少しずつ減らしていき、0より大きい間は発動できないようにする

コードにすると、次のようなイメージになります。

public class SkillController : MonoBehaviour
{
    [SerializeField] private float cooldownTime = 5f; // クールダウンの秒数
    private float currentCooldown = 0f;

    void Update()
    {
        // クールダウン中は少しずつ減らしていく
        if (currentCooldown > 0f)
        {
            currentCooldown -= Time.deltaTime;
        }

        if (Input.GetKeyDown(KeyCode.Space))
        {
            UseSkill();
        }
    }

    void UseSkill()
    {
        // クールダウン中は発動させない
        if (currentCooldown > 0f) return;

        Debug.Log("スキル発動!");
        currentCooldown = cooldownTime;
    }
}

ポイントは、UseSkill()の先頭で「クールダウン中かどうか」をチェックしていることです。この1行があるだけで、待ち時間中の発動をしっかり防げます。

もしUIにクールダウンの残り時間を表示したい場合は、currentCooldownの値をそのままテキストやゲージに反映させれば対応できます。

UniRxは使ったほうがいい?

クールダウンについて調べていると、「UniRx」というライブラリを使った実装例を見かけることもあるかもしれません。これは、値の変化を監視しやすくするためのライブラリで、Unityでよく使われています。

結論から言うと、単純に発動を制限したいだけであれば、先ほどのような素のC#での実装で十分です。

一方で、次のようなケースでは、UniRxを使うとコードがすっきりまとまりやすくなります。

  • クールダウンの残り時間に応じて、UIやアニメーションを細かく切り替えたい
  • 複数の場所で「クールダウンが終わった瞬間」を検知したい

つまり、UniRxは「使わないと実装できないもの」ではなく、「監視したい処理が増えてきたときに検討する選択肢のひとつ」と考えておくとよいでしょう。まずは素のC#で動かしてみて、必要性を感じてから導入を検討しても遅くありません。

クールダウンが明けた瞬間に、光るエフェクトや魔法陣のような演出を加えると、プレイヤーにも「使える状態になった」ということが視覚的に伝わりやすくなります。こうした演出パーツは、Asset Storeで手頃なものを探してみるのもおすすめです。

Super Realistic ARPG FX Bundle – 1000+ Unique VFX!
✅ Asset Storeでチェックする




連打・多重発動を防ぐ実装

クールダウンの実装ができたら、次に気をつけたいのが「連打による多重発動」です。クールダウン中でなくても、スキル発動中にもう一度ボタンを押してしまうと、演出が重なって表示がおかしくなったり、処理が二重に走ってしまうことがあります。

これを防ぐには、「今スキルを実行中かどうか」を表すフラグを1つ用意し、実行中は新しい入力を受け付けないようにするのがシンプルな方法です。

public class SkillController : MonoBehaviour
{
    private bool isSkillRunning = false;

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            UseSkill();
        }
    }

    void UseSkill()
    {
        // 実行中なら新しい入力は無視する
        if (isSkillRunning) return;

        StartCoroutine(SkillRoutine());
    }

    System.Collections.IEnumerator SkillRoutine()
    {
        isSkillRunning = true;

        Debug.Log("スキル発動!");
        yield return new WaitForSeconds(1.0f); // 演出時間など

        isSkillRunning = false;
    }
}

ここでのポイントは、UseSkill()の先頭にあるガード節です。isSkillRunningがtrueのあいだは、それ以降の処理を実行せずにそのまま抜けるようにしています。この1行を入れておくだけで、連打による多重発動をかなり防げます。

もしこのガード節を入れずに実装してしまうと、ボタンを連打したぶんだけコルーチンが何度も走り出し、エフェクトやサウンドが重なって再生されたり、ダメージ判定が想定より多く発生したりする、といった不具合につながりやすくなります。

フラグ管理で対応しきれなくなったら

ここまで紹介したフラグ管理は、スキルが数個程度のうちはこれで十分対応できます。ただ、コンボの途中でだけキャンセルを許可したい、といったように条件が細かくなってくると、bool変数1つだけでは管理しきれなくなってくることがあります。

そうなったタイミングで初めて、処理をひとつのオブジェクトとして扱う「Commandパターン」や、状態ごとに処理をまとめる「ステートマシン」の導入を検討してみるとよいでしょう。今の実装で困っていないうちは、無理に取り入れる必要はありません。

こうした設計パターンについて体系的に学んでおくと、スキルシステム以外の場面でも応用が利くようになります。

Game Programming Patterns 
✅ Amazonでチェックする✅ 楽天でチェックする




まとめ

クールダウンは待ち時間の管理、キャンセル処理は多重発動の防止と、それぞれ役割が違う仕組みだということを押さえておくと、実装の見通しが立てやすくなります。

スキルの数が少ないうちは、enumやフラグを使ったシンプルな実装で十分対応できます。管理が難しくなってきたと感じたタイミングで、ステートマシンやCommandパターンといった設計を検討してみてください。

まずは今回紹介したコードをベースに、自分のプロジェクトのスキルに合わせて調整しながら試してみてください。


よくある質問(FAQ)

Q
クールダウン中でも他のスキルは使えるようにすべきですか?
A

これはゲームの設計次第で、どちらが正解というわけではありません。

スキルごとに個別のクールダウン変数を持たせれば、あるスキルが待ち時間中でも別のスキルは問題なく使えます。

一方で、複数のスキルをまとめて1つのクールダウンで管理する方法もあり、この場合はどれか1つを使うと他のスキルも一緒に待ち時間に入ります。

連続でスキルを撃たれすぎるのを防ぎたい場合は共通クールダウン、テンポよく色々なスキルを使わせたい場合は個別クールダウンが向いています。

Q
クールダウン完了のタイミングで演出を入れるにはどうすればいいですか?
A

Update内で、クールダウンの変数が0より大きい状態から0以下になった瞬間を判定してあげると実現できます。

たとえば、前のフレームの値を変数に保存しておき、「前フレームは0より大きかったのに、今フレームは0以下になった」というタイミングを見つけて、そこでエフェクトの再生やUIの更新処理を呼び出す、という形です。

UniRxを使う場合は、値の変化を監視する仕組みが用意されているため、このあたりの判定をより簡潔に書くこともできます。

Q
ライブラリを使わずに大規模なスキルシステムは作れますか?
A

作ること自体は可能ですが、スキルの種類や演出が増えるほど、if文やフラグの数も比例して増えていき、保守がだんだん大変になっていきます。

目安として、スキルが5個を超えてきたり、演出やUIとの連動が複雑になってきたりしたタイミングで、ステートマシンのようなライブラリの導入を検討してみると、コードの見通しを保ちやすくなります。

※当サイトはアフィリエイト広告を利用しています。リンクを経由して商品を購入された場合、当サイトに報酬が発生することがあります。

※本記事に記載しているAmazon商品情報(価格、在庫状況、割引、配送条件など)は、執筆時点のAmazon.co.jp上の情報に基づいています。
最新の価格・在庫・配送条件などの詳細は、Amazonの商品ページをご確認ください。

スポンサーリンク