【Unity】コルーチンと Task.Delay() を使用したサンプルコード

2025年3月28日

コルーチンと Task.Delay() を使用した簡単なサンプルコードになります

サンプルコード

このコードは、Unityで一定間隔ごとにオブジェクトを生成する機能を実装しています。Startメソッドでコルーチンを起動し、SpawnObjects内の無限ループにより毎秒、指定されたプレハブ(objectPrefab)がスクリプトがアタッチされたオブジェクトの位置に無回転で生成されます。

コルーチンの例

using UnityEngine;
using System.Collections;

public class Example : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(SpawnObjects());
    }

    IEnumerator SpawnObjects()
    {
        while (true)
        {
            // オブジェクトを生成
            Instantiate(objectPrefab, transform.position, Quaternion.identity);
            // 1秒待機
            yield return new WaitForSeconds(1);
        }
    }
}

このコードは、Unityのスクリプトで、ゲームオブジェクトを一定間隔で生成(スポーン)するためのものです。以下に各部分の説明を示します。

usingディレクティブ

  • using UnityEngine;
    Unityの基本的な機能(ゲームオブジェクト、コンポーネント、物理演算など)を利用するために必要な名前空間をインポートしています。
  • using System.Collections;
    コルーチン(非同期処理)で使用される IEnumerator を利用するために必要な名前空間です。

クラス宣言

  • public class Example : MonoBehaviour
    このスクリプトは MonoBehaviour を継承しているため、Unityのコンポーネントとしてシーン内のゲームオブジェクトにアタッチして利用できます。

Startメソッド

  • void Start()
    Unityのライフサイクルメソッドの一つで、スクリプトが有効になったときに一度だけ呼ばれます。
    • この中で StartCoroutine(SpawnObjects()); を呼び出しており、SpawnObjects という名前のコルーチンを開始します。

コルーチン SpawnObjects

  • IEnumerator SpawnObjects()
    コルーチンは通常のメソッドと異なり、途中で処理を一時停止し、後で再開することが可能です。
    • while (true) ループ内で無限ループを作っており、永遠に実行される設計になっています。
    • ループ内で、Instantiate(objectPrefab, transform.position, Quaternion.identity); によって、objectPrefab(プレハブで定義されたオブジェクト)が、スクリプトがアタッチされているオブジェクトの位置(transform.position)に生成されます。Quaternion.identity は、回転が「無回転」の状態であることを意味します。
    • yield return new WaitForSeconds(1); により、次のオブジェクト生成前に1秒間の待機が行われます。これによって、1秒ごとに新しいオブジェクトが生成されることになります。

注意点

  • objectPrefabの宣言
    のコードスニペットには objectPrefab の宣言が含まれていません。実際に利用する場合は、例えば public GameObject objectPrefab; のように宣言し、Unityのインスペクターから対象のプレハブを割り当てる必要があります。

全体の流れ

  1. ゲームが開始すると、Start メソッドが実行され、SpawnObjects コルーチンが開始される。
  2. コルーチン内の while (true) ループが実行され、無限に処理が繰り返される。
  3. 各ループで、objectPrefab が現在の位置に生成され、1秒待機される。
  4. これにより、ゲーム中に定期的に新しいオブジェクトが生成される仕組みとなる。

このスクリプトは、敵キャラクターやアイテムのスポーンなど、さまざまな用途に応用することができます。

次のようなのを作ってみましょう
ただし、動作させるためには上記コードに加筆修正、またシーンの作り込みが必要です

Task.Delay()の例

using System.Threading.Tasks;

public class Example : MonoBehaviour
{
    async void Start()
    {
        while (true)
        {
            // オブジェクトを生成
            Instantiate(objectPrefab, transform.position, Quaternion.identity);
            // 1秒待機
            await Task.Delay(1000);
        }
    }
}

これらの例では、1秒ごとにオブジェクトを生成するために、コルーチンと Task.Delay() を使用しています。コルーチンでは、yield return new WaitForSeconds(1) を使用して、1秒待機しています。一方、Task.Delay()では、await Task.Delay(1000)を使用して、1秒待機しています。

使い分け

コルーチンと Task.Delay() は、いずれも時間的な制御を実現するために使用されることがありますが、適切な使用方法については、以下のようなポイントに注意する必要があります。

  1. ゲームオブジェクトのアクションを実行する場合は、コルーチンを使用することが推奨されます。コルーチンはUnityの独自の機能であり、Unityのフレームワークに合わせて設計されています。また、物理演算などの時間的な制御も含まれます。
  2. C#の標準機能を使用してタスクを実行する場合は、Task.Delay()を使用することが推奨されます。Task.Delay()は、単純な時間的な遅延処理を実現するために使用されます。
  3. コルーチンは、複数の yield return文を使って、処理を一時停止することができます。一方、Task.Delay()は、awaitキーワードを使用して、タスクの継続を待機することができます。コルーチンは、複雑な制御構造を必要とする場合に有用ですが、単純な遅延処理には適していません。
  4. コルーチンは、通常、IEnumeratorインターフェイスを使用して定義されます。一方、Task.Delay()は、async/await構文を使用して定義されます。コルーチンは、Unityのフレームワークに合わせて設計されたものであり、Unityのゲームオブジェクトに対する制御を容易にします。

総合すると、コルーチンと Task.Delay() の使い分けは、主に以下の要因によって決まります。

  1. ゲームオブジェクトのアクションを実行する場合は、コルーチンを使用することが推奨されます。
  2. 単純な時間的な遅延処理を実現する場合は、Task.Delay()を使用することが推奨されます。
  3. 複雑な制御構造を必要とする場合は、コルーチンを使用することが推奨されます。
  4. Unityのフレームワークに合わせて設計されたものであるコルーチンは、ゲーム開発において非常に重要です。一方、Task.Delay()は、一般的なC#プログラミングにも使用されるため、汎用性が高くなっています。

止める必要がある場合

break;で止める

while文のブロック中にbreakを実行するif文を挿入することでも実現できます

コードで止める

コルーチンを停止する方法

using UnityEngine;
using System.Collections;

public class Example : MonoBehaviour
{
    private IEnumerator coroutine;

    void Start()
    {
        coroutine = SpawnObjects();
        StartCoroutine(coroutine);
    }

    IEnumerator SpawnObjects()
    {
        while (true)
        {
            // オブジェクトを生成
            Instantiate(objectPrefab, transform.position, Quaternion.identity);
            // 1秒待機
            yield return new WaitForSeconds(1);
        }
    }

    void StopCoroutine()
    {
        StopCoroutine(coroutine);
    }
}

コルーチンを停止するには、StopCoroutine() メソッドを使用します。StopCoroutine() メソッドにコルーチンのオブジェクトを渡すことで、コルーチンを停止できます。

Task.Delay()を停止する方法

using System.Threading;
using System.Threading.Tasks;

public class Example : MonoBehaviour
{
    private CancellationTokenSource cts;

    async void Start()
    {
        cts = new CancellationTokenSource();

        while (!cts.IsCancellationRequested)
        {
            // オブジェクトを生成
            Instantiate(objectPrefab, transform.position, Quaternion.identity);
            // 1秒待機
            await Task.Delay(1000, cts.Token);
        }
    }

    void StopTask()
    {
        cts.Cancel();
    }
}

Task.Delay()を停止するには、CancellationTokenSourceを使用します。CancellationTokenSourceは、Cancel() メソッドを呼び出すことで、Task.Delay()を停止できます。Task.Delay()には、CancellationTokenSource.Tokenを渡すことで、キャンセル要求をトークンに伝えることができます。

以上のサンプルコードは、それぞれの機能を停止するための基本的な方法を示しています。実際には、ゲームやアプリケーションに合わせて、停止方法をカスタマイズする必要があります。

このコードでは、オブジェクトが破棄されても自動的にタスクがキャンセルされる仕組みにはなっていません。そのため、オブジェクト破棄後に非同期処理が継続し、たとえば transform.position などの参照が無効になるとエラーが発生する可能性があります。

対策:

  • OnDestroy でキャンセル: MonoBehaviour の OnDestroy メソッド内で cts.Cancel() を呼び出すことで、オブジェクトが破棄される際に非同期タスクを正しく停止させるようにしてください。
  • 例外処理: キャンセル後の TaskCanceledException を適切にハンドリングするのも推奨されます。

このようにすれば、オブジェクトが破棄された時に非同期タスクが不適切に動作するのを防げます。