UnityのInvokeメソッドをわかりやすく解説

ゲーム開発

はじめに

皆さんはUnityでゲームオブジェクトの動作タイミングをコントロールする場面に悩んだことはないでしょうか。 C#スクリプトで一定の時間が経過してから特定の処理を実行したいとき、Unity Invoke という機能が役立ちます。 たとえば数秒後に敵キャラクターを発生させたい場合など、Invokeを使うとシンプルなコードでタイミングを調整できます。 初心者の方でも比較的とっつきやすい機能なので、まずはゲーム開発におけるInvokeの概要を理解しておくといいかもしれません。 ここでは実務でもよく使われるシーンとあわせて、Invokeのメリットや使い方をわかりやすく説明していきます。

UnityにおけるInvokeとは

UnityのC#スクリプトにおいて、Invoke は特定のメソッドを指定時間後に実行してくれる仕組みです。 MonoBehaviourを継承したクラスであれば、Invoke("メソッド名", 秒数) のように書くだけで、そのメソッドを一定時間後に呼び出せます。 たとえば、ある演出や演出後の結果処理をタイムラグをつけて呼び出すといった用途で利用されます。 また、引数を直接渡すことはできませんが、柔軟なコーディングでカバーする方法はいろいろあります。

遅延実行が可能

Invokeは「何秒後にこの処理を実行したい」といった、とてもシンプルな要求に対応してくれます。 コルーチンやUpdateメソッドで代替する方法もありますが、比較的簡単に書ける点でInvokeが使われることが多いようです。 演出と処理の順番を分けて管理したいときなどにも便利ですね。

再帰呼び出しとの違い

Invokeとは別に、自分自身のメソッドをループ的に呼び出す再帰構造を組むことも可能です。 ただし、再帰呼び出しはコードが複雑になりがちで、処理が終わらなくなるリスクもあります。 Invokeを使うことで、シンプルにゲームループのタイミングを組み立てられるため、リーダブルなコードが書きやすくなるでしょう。

実務でのメリット

ゲームやシミュレーションの実務でInvokeを使うメリットは複数あります。 ここでは代表的なものを挙げてみましょう。

  • 遅延呼び出しが直感的に書ける
  • コルーチンを使わなくても短いコードで済ませられる
  • アニメーションや演出とのタイミング調整がやりやすい

上記のように、シンプルに時間指定で処理を行いたいときはInvokeがとても便利です。 ただし細かな時間精度が必要になるケースでは別の方法を検討することも多いので、使いどころをよく見極めましょう。

サンプルケース:一定間隔でオブジェクト生成

敵キャラクターやアイテムを数秒ごとに出現させたい場合があるかもしれません。 Invokeを使うと、メソッドをループ実行させる仕組みを手軽に作れます。 具体的には、InvokeRepeating という関連メソッドを使うと便利です。 これについては後ほど詳しく説明しますが、実際のゲーム開発ではこうしたシーンでよくInvokeが使われています。

他の仕組みと組み合わせる

演出やアニメーションで使われる方法として、Invokeとアニメーターのトリガーを連動させる手もあります。 特定のタイミングでイベントを挿入し、その直後に画面効果を差し込む場合などに有効です。 また、物理演算と組み合わせると、衝突後にしばらくしてから爆発エフェクトを表示するといった表現も実装できます。

基本的な使い方

Invokeの使い方はとてもシンプルで、メソッド名と時間(秒)を指定するだけです。 MonoBehaviourを継承したクラス内で、以下のように記述できます。

必要なメソッドを定義

まずは呼び出したいメソッドを定義します。 返り値はvoidでOKです。 引数はとれないので、外部の変数やクラスのプロパティなどを使って必要な情報を取得させます。

void SpawnEnemy()
{
    // 敵キャラクターを生成する処理
    Debug.Log("敵キャラクターが出現しました");
}

ここでは敵キャラクターを生成する処理を仮で書いています。 実際には Instantiate を使ってPrefabを生成するイメージです。

Invokeの書き方

呼び出し元のクラスで、Invoke("SpawnEnemy", 3f) のように書くだけで、3秒後にSpawnEnemyメソッドが呼ばれます。 メソッド名は文字列で指定する点に注意してください。 以下は具体例です。

public class EnemySpawner : MonoBehaviour
{
    void Start()
    {
        // 3秒後に敵キャラクターを出現させる
        Invoke("SpawnEnemy", 3f);
    }

    void SpawnEnemy()
    {
        // 敵キャラクターを生成する処理
        Debug.Log("敵キャラクターが出現しました");
    }
}

このコードでは、Startメソッドが呼ばれてから3秒後にSpawnEnemyが実行されます。 文字列を指定するため、呼び出すメソッド名の入力ミスには気をつけましょう。

InvokeRepeatingによる繰り返し実行

Invokeには、指定時間ごとに処理を繰り返すための InvokeRepeating というメソッドも用意されています。 これは定期的に同じメソッドを実行したい場合に便利です。

書き方の流れ

InvokeRepeating("メソッド名", 開始までの遅延時間, 繰り返しの間隔);

たとえば、2秒後に初回実行し、その後は5秒ごとに繰り返したい場合は次のように書きます。

public class ItemDropper : MonoBehaviour
{
    void Start()
    {
        // 2秒後に初回実行し、それ以降5秒おきに繰り返し呼び出す
        InvokeRepeating("DropItem", 2f, 5f);
    }

    void DropItem()
    {
        Debug.Log("アイテムをドロップしました");
        // 実際にはInstantiateなどを使ってアイテム生成を行う
    }
}

アイテムを生成したい場合や、定期的にプレイヤーのステータスを更新したい場合などに役立つでしょう。

CancelInvokeで停止可能

繰り返しを停止したいときは CancelInvoke("メソッド名") を呼び出します。 これを呼べば該当メソッドのInvoke(単発呼び出しも含む)がキャンセルされるため、繰り返し実行を止められます。 ゲーム途中で条件を満たしたらInvokeを解除したいケースで便利です。

実装時の注意点

Invokeはシンプルで使いやすいものの、いくつか注意すべきポイントがあります。 大きく分けて次のような点が挙げられます。

  • メソッド名を文字列で指定するため、タイプミスに注意する
  • 何度もInvokeRepeatingすると重複して呼ばれる可能性がある
  • 非同期処理のように任意のタイミングで制御するには向いていない

タイプミスを防ぐためには、スクリプトの可読性を高める工夫が求められます。 たとえば一定時間待ったあとにまた別の遅延呼び出しを行う場合は、コードの流れが複雑にならないよう意識して書きましょう。

タイミング精度に限界がある

Invokeのタイミングはフレーム更新の仕組みに左右されるため、完全に厳密な秒数制御にはあまり向きません。 重要な場面での時間管理にはコルーチンや固定フレームレートを利用した管理を検討するといいですね。 ただし、一般的なゲーム演出ではInvokeの誤差はそこまで問題にならない場合が多いです。

途中でオブジェクトが破棄されるケース

MonoBehaviourをアタッチしたゲームオブジェクトが破棄されると、Invokeの呼び出しも失敗したり、エラーを引き起こすケースがあります。 Prefabを乱暴にDestroyしたりシーンを移行するときなど、オブジェクトのライフサイクルに注意しましょう。

オブジェクトのOnDestroyやシーン切り替えのタイミングを意識して設計すると、予期せぬ動作を減らせます。

よくある使い方のバリエーション

実際の開発では、次のような使い方が多いです。 どれもUnity特有のフレーム処理を理解しつつ、時間を扱う方法として重宝されています。

シンプルな一回呼び出し

特定のイベントを遅らせたいときに便利です。 演出シーンの切り替えや一時的なメッセージ表示などに役立ちます。

定期的に実行する処理

InvokeRepeatingを利用して、アイテム生成や敵AIの定期更新を行うケースがあります。 ただし、時間に厳密な処理には向かないことが多いので、開発の要件に合わせてほかの手法も検討してください。

CancelInvokeの利用

定期処理をある条件で止める必要があるなら、CancelInvokeが有用です。 プレイヤーが特定エリアに入ったら敵の出現を止める、などの演出にも使えます。

他の方法との比較

Unityでは時間経過を扱う方法として、コルーチンStartCoroutine)を使う方法や、Updateメソッド で時間を計算しながら処理する方法があります。 どれを選ぶかは開発の規模や処理の内容によって変わるので、以下のポイントを意識すると良いかもしれません。

Invoke

簡単な遅延実行や繰り返しに向いています。 たとえば、敵キャラクターの出現を3秒後に行いたい場合は、Invoke("SpawnEnemy", 3f) と書けます。

コルーチン

複雑なフローや待ち時間を伴う処理に適しています。 ちなみに、コルーチンはInvokeと同じように、InvokeRepeatingやCancelInvokeといったメソッドも用意されています。

Updateメソッド

タイマーを自前で実装することになります。 細かい時間制御やステート管理が可能です。

簡単なタイミング制御ならInvoke、複雑なフロー管理ならコルーチン、細かい制御やパフォーマンス重視ならUpdateやFixedUpdateと組み合わせるといったイメージです。

小規模ゲームならInvokeが便利

個人制作や小規模プロジェクトであれば、Invokeの手軽さは魅力的です。 大掛かりな演出管理が必要な際にはコルーチンのほうが柔軟ですが、まずはInvokeを使ってみると理解が深まるでしょう。

始めのうちはシンプルな方法から取り入れていくとコードが見やすくなります。

トラブルシューティング

Invokeを使ううえで発生しやすいトラブルの例をいくつか紹介します。 初心者がつまづきやすいポイントを事前に押さえておくと、デバッグの時間を大幅に節約できます。

タイプミスによる呼び出し失敗

Invoke("SpawnEnemy", 3f); のように書くとき、"SpawnEnmey" のように綴りを間違えてしまうと動きません。 コンパイルエラーにはならず、実行時に何も起こらないので気づきにくいのが厄介です。 メソッド名を変更したときは、Invokeの呼び出し名も合わせてチェックしましょう。

想定外の多重呼び出し

InvokeRepeating を複数回呼び出してしまい、同じメソッドが何重にも動いていることがあります。 デバッグログを見て「なぜか呼び出し回数が増えている」という場合は、同じメソッドのInvokeRepeatingが重複していないか確認してください。 必要があれば CancelInvoke を使って一旦リセットする方法も検討しましょう。

シーン切り替え時の動作

シーンが切り替わると、MonoBehaviourがアタッチされているゲームオブジェクトが破棄されます。 そのため、シーンをまたいだInvokeの動作を期待しないようにしてください。 もしシーンを超えてもオブジェクトが生き続ける必要がある場合は、DontDestroyOnLoad を使うなど別の仕組みを考えましょう。

コード例:敵の定期出現

ここでは、一定の時間ごとに敵を出現させる実装例を示します。 あくまでサンプルなので、内容を自由にアレンジしてみてください。

using UnityEngine;

public class EnemyManager : MonoBehaviour
{
    // Inspectorで設定した敵のPrefab
    public GameObject enemyPrefab;

    // 最初の出現までの遅延時間
    [SerializeField]
    private float initialDelay = 3f;

    // 出現間隔
    [SerializeField]
    private float repeatRate = 5f;

    void Start()
    {
        // 一定時間ごとに敵を出現させる
        InvokeRepeating("SpawnEnemy", initialDelay, repeatRate);
    }

    void SpawnEnemy()
    {
        if (enemyPrefab != null)
        {
            // プレイヤーの周囲など位置を決めて Instantiate
            Instantiate(enemyPrefab, new Vector3(0, 0, 0), Quaternion.identity);
            Debug.Log("敵キャラクターを出現させました");
        }
        else
        {
            Debug.LogWarning("enemyPrefabが設定されていません");
        }
    }

    // ある条件で敵の出現をストップするメソッド
    public void StopSpawning()
    {
        CancelInvoke("SpawnEnemy");
        Debug.Log("敵の出現を停止しました");
    }
}

このスクリプトを空のGameObjectなどにアタッチし、enemyPrefab に敵キャラクターのPrefabを割り当ててください。 StopSpawning メソッドは外部から呼び出すことで停止処理ができます。 たとえばボスステージに移行したタイミングなどで呼び出すと良いでしょう。

おすすめのデバッグ方法

Invokeに関連する不具合の多くは、メソッド名の誤りや想定外のタイミングでの呼び出しが原因です。 次のようにデバッグログを活用すると、症状をすばやく突き止められます。

  • Invokeを呼び出す箇所にログを仕込んで、実際に呼び出されているか確認する
  • Invokeされた先のメソッドにもログを入れ、何度呼び出されているか追跡する
  • CancelInvokeが正常に動いているかをDebugログでチェックする

これらを使うだけでもかなり動作がつかみやすくなります。 みなさんもぜひ試してみてください。

まとめ

Unity Invoke は、簡単に遅延処理や定期的な処理を実装できる便利な仕組みです。 実務でも、小規模プロジェクトの演出やテスト的な動作確認に使われることが多いでしょう。 InvokeRepeatingによる繰り返し実行とCancelInvokeによる停止を活用すれば、複雑なコルーチンを組むほどでもない場面で効率的に開発を進めることができます。

一方で、メソッド名を文字列で指定する点や時間精度の問題など、注意すべき部分もあります。 大規模なプロジェクトや厳密な時間管理が必要な場面では、コルーチンやUpdateメソッドなどほかの方法も検討してください。 まずはUnityの基本機能としてInvokeを理解し、適切なシーンで活用してみると、ゲーム開発がよりスムーズになるのではないでしょうか。

Unityをマスターしよう

この記事で学んだUnityの知識をさらに伸ばしませんか?
Udemyには、現場ですぐ使えるスキルを身につけられる実践的な講座が揃っています。