Unityに関連する記事です

1.コルーチンとは?


 コルーチン(Coroutines)は、非同期処理を実装するための特別なメソッドです。
通常のメソッドとは異なり、コルーチンは一時停止でき、後で再開できる特徴を持っています。

 そのためコルーチンは、ゲーム内で時間経過に合わせて何かを実行するための方法の1つとして利用できます。
通常のメソッドが実行されると、その処理が終わるまでゲーム全体が一時停止します。
ですが、コルーチンを使うと、ゲームの進行をブロック(停止)せずに時間のかかるタスクを実行できます。

 これは、ゲーム内で時間の経過に合わせて何かを実行したり、特定のアクションやイベントを指定した条件を満たすまで待機させたりすることが出来ます。


2.非同期処理とは?


 非同期処理は、コードが他の処理をブロックせずに実行できる処理方法です。
これは主に、ユーザーインターフェースのレスポンス性を向上させるために使用されます。

 コルーチンは非同期処理を実現する方法の一つで、待ち時間のあるタスクを逐次的に実行できます。



 別の方向からも考えてみましょう。

 非同期処理は、待ち時間のあるタスクを実行する方法です。
これは、ゲーム内で何かを待機しながら他のことをする場合に役立ちます。

 例えば、プレイヤーキャラクターが移動している際に、ゲーム全体を停止してしまうとゲームが成立しなくなりますが、
移動処理を阻害せず、特定の処理だけを遅延処理することが可能になります。


3.同期処理と非同期処理の違い


 同期処理は、タスクが順番に実行され、前のタスクが完了するまで次のタスクが実行されません。
これは今までに書いているソースコードの処理のことです。上から順に処理され、その処理が終わるまでは下の行の処理は動きません
これはシンプルで直感的ですが、長時間の待機がある場合にアプリケーション全体がフリーズしてしまう可能性があります。

 非同期処理は、タスクが完了しなくても次のタスクが実行できるため、アプリケーションのレスポンス性が向上します。
つまり、命令だけしておいて、その処理の終了は待たずに下の行の処理を実行します。



 ここではそれぞれについて、例を挙げて説明します。

 同期処理は、自動車が交差点を通過するのに似ています。
交差点には信号があり、赤信号のときには一方の道路の車両が停止し、緑信号のときにはもう一方の道路の車両が進行できます。

 この場合、信号が交差点全体を制御しており、各車両は信号の状態に合わせて進行または停止を決定します。
つまり、一つの車両が交差点を通過するのを待たなければならず、信号の状態に依存しています。これが同期処理です。

 同様に、同期処理では一つのタスクが完了するのを待ち、その後次のタスクが実行されます。
他のタスクは、前のタスクが終了するまで待機する必要があります。



 非同期処理は、洗濯機で洗濯をするのに似ています。
洗濯機に洗濯物を入れ、洗濯モードを設定したら、スタートボタンを押します。
その後、洗濯機は洗濯を始め、あなたは自由に他のことをすることができます。
つまり、洗濯機が洗濯を続けている間、あなたは別のタスクに取り組むことができます。

 非同期処理では一つのタスクが完了するのを待つ必要がなく、他のタスクを同時に実行できます
非同期処理は、待ち時間がある場合や、複数のタスクを同時に処理したい場合に非常に便利です。



 以上のように、同期処理はタスクが順番に実行され、前のタスクが完了するまで待たなければならず、非同期処理はタスクが完了しなくても他のタスクを実行できます。


4.コルーチンメソッドの定義と実行方法


 コルーチンを定義し、実行するための基本的な書式を示します。


<1.コルーチンメソッドの定義>


 コルーチンを定義するには、通常のメソッドと同じようにメソッドを定義しますが、
戻り値の型を IEnumerator(「アイ・イニュメレーター」と読むことが一般的です) にします

 また、コルーチン内で待機するために yield(「イールド」と読むことが一般的です) ステートメントを使用します。


using System.Collections;
using UnityEngine;

public class Example : MonoBehaviour
{
    // コルーチンメソッドの定義
    IEnumerator MyCoroutine()  // 戻り値の型に注目
    {
        // コルーチンの中で待機する
        yield return new WaitForSeconds(2.0f);  // yield を利用した処理を記述することで待機できる
        
        // その他の処理
        Debug.Log("待機終了");
    }
}

 yield return new WaitForSeconds(2.0f) とはよく利用される書式で、引数内の時間だけ処理を中断して、
待機後、その次に書かれている処理を実行します。

 上記の例であれば、MyCoroutine メソッドを実行すると、2秒処理を中断して待機し、その後、待機終了のログが表示されます。


<2.コルーチンの実行>


 コルーチンを実行するには、StartCoroutine メソッドを使用し、引数内に実行したいコルーチンメソッドを指定します。

 以下は、コルーチンを実行する例です。


public class Example : MonoBehaviour
{
    IEnumerator MyCoroutine()
    {
        yield return new WaitForSeconds(2.0f);
    }

    void Start()
    {
        // コルーチンの実行
        StartCoroutine(MyCoroutine());
    }
}

 このコードでは、StartCoroutine メソッドを使用して MyCoroutine コルーチンを実行しています。
コルーチン内の yield return ステートメントによって、指定した待機時間が経過した後にコルーチンが再開されます。

 コルーチン内で待機するためには、yield return ステートメントを使って、WaitForSeconds や他の待機命令を指定します。
これにより、ゲーム内で時間に基づいた非同期処理やアニメーション制御などが可能になります。



 実行するコルーチンメソッドに引数がある場合には、通常のメソッドと同様に引数を指定することができます。

 以下は、引数を伴うコルーチンメソッドを実行するサンプルコードです。


using System.Collections;
using UnityEngine;

public class Example : MonoBehaviour
{
    // 引数を受け取るコルーチンメソッドの定義
    IEnumerator MyCoroutine(int count)
    {
        for (int i = 0; i < count; i++)
        {
            // 何かの処理
            Debug.Log("Step " + i);

            // ここで待機
            yield return new WaitForSeconds(1.0f);
        }
    }

    void Start()
    {
        // 引数を指定してコルーチンの実行
        int numberOfSteps = 3; // 例: 3回繰り返す
        StartCoroutine(MyCoroutine(numberOfSteps));
    }
}

 この処理を実行すると、1秒おきに Step 0、Step 1、Step 2 と表示されていきます。


<3.yield ステートメント>


 yield ステートメントは、C#のコルーチン内で使用する特別なキーワードであり、IEnumerator メソッド内でのみ使用できます。
また、コルーチン内で yield ステートメントを少なくとも1回使用する必要があります

 以下に、正しい構文とエラーの構文を示します。


 <正しい構文>

using System.Collections;
using UnityEngine;

public class Example : MonoBehaviour
{
    // コルーチンメソッドの定義
    IEnumerator MyCoroutine()
    {
        // ここで yield ステートメントを使用する
        yield return new WaitForSeconds(2.0f);
        
        // その他の処理
    }

    void Start()
    {
        // コルーチンの実行
        StartCoroutine(MyCoroutine());
    }
}

 上記のコードは正しい構文です。
MyCoroutine メソッド内で yield ステートメントが使用されており、コルーチン内で非同期処理を行うために正しく構造化されています。



 <エラーの構文 

using System.Collections;
using UnityEngine;

public class Example : MonoBehaviour
{
    // エラー: IEnumerator 内で yield ステートメントが不足
    IEnumerator MyCoroutine()
    {
        // ここで yield ステートメントを使用しない
    }

    void Start()
    {
        // エラー: コルーチン内で yield ステートメントが不足
        StartCoroutine(MyCoroutine());
    }
}

 上記のコードはエラーの構文です。
MyCoroutine メソッド内で yield ステートメントが不足しており、コルーチンが適切に機能しないため、構文エラーが発生します。



 <エラーの構文◆

using System.Collections;
using UnityEngine;

public class Example : MonoBehaviour
{
    IEnumerator MyCoroutine()
    {
        yield return new WaitForSeconds(2.0f);
    }

    void Start()
    {
        // コルーチンメソッドが実行されない
        MyCoroutine();
    }
}

 上記のコードは、構文エラーは発生しませんが、コルーチンメソッドが実行されません
理由は、コルーチンメソッドを実行する際に StartCoroutine メソッドを利用していないためです。

 特にこのエラーの場合、処理自体のエラーは出ず、くわえてログにもエラーメッセージは表示されませんので、
コルーチンメソッドが実行されない理由に気づけない可能性があります。特に注意が必要です。



 正しいコルーチンの構文を理解することで、非同期処理を制御するためにコルーチンを適切に使用できるようになります。


5.コルーチンを活用したゲーム内の実装例


 以下は、コルーチンを使用してゲーム内で一般的に行われるタスクを実行するサンプルコードです。


<1.一時的な待機>


using UnityEngine;
using System.Collections;

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

    IEnumerator WaitAndDoSomething()
    {
        yield return new WaitForSeconds(2f); // 2秒待機
        Debug.Log("2秒待機後に何かを実行");
    }
}


<2.アニメーションの制御>



using UnityEngine;
using System.Collections;

public class Example : MonoBehaviour
{
    private Animator animator;

    void Start()
    {
        animator = GetComponent<Animator>();
        StartCoroutine(PlayAnimation());
    }

    IEnumerator PlayAnimation()
    {
        yield return new WaitForSeconds(1f);
        animator.Play("Run"); // アニメーション再生
    }
}


<3.非同期読み込み>



using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;

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

    IEnumerator LoadLevelAsync()
    {
        AsyncOperation asyncLoad = SceneManager.LoadSceneAsync("Level2");
        while (!asyncLoad.isDone)
        {
            float progress = Mathf.Clamp01(asyncLoad.progress / 0.9f);
            Debug.Log("読み込み進捗: " + (progress * 100) + "%");
            yield return null;
        }
    }
}


6.コルーチンを利用時の注意


 コルーチンを利用する際には、以下の注意点に気を付けてください。

 コルーチンメソッドを利用するためには、MonoBehaviour クラスを継承している必要があります。

 ゲームオブジェクトが破壊された場合、コルーチンも停止します。これを防ぐためにオブジェクトの状態を確認しましょう。
これは命令を出したゲームオブジェクトと、命令を受けたゲームオブジェクトが異なる場合に特に注意が必要です。
その場合、両方のゲームオブジェクトが存在していないとコルーチンの処理は停止します。

 例えば、プレイヤー用のスクリプト内にコルーチンメソッドが用意されており、それを敵側のスクリプトから実行すると考えてください。
敵のゲームオブジェクトは破壊されてしまうと、一緒にアタッチされているスクリプトも破棄されます。
このとき、敵側のスクリプトからプレイヤー用のスクリプト内のコルーチンメソッドが実行されている場合、
敵のゲームオブジェクトが破壊されると同時にコルーチンメソッドの処理も停止します。

 よって、外部のスクリプトからコルーチンメソッドを実行する場合にはリスクが伴いますので、
なるべく外部のスクリプトからは直接実行せず、プレイヤーのスクリプトの別のメソッドを経由して、スクリプト内部からコルーチンメソッドを実行するようにしましょう。


7.まとめ


 コルーチンは、ゲーム開発において非同期処理を実装するための強力なツールです。
タイミングやアニメーション、非同期読み込みなど、さまざまなシナリオで活用できます。

 初めてコルーチンを使う際には、上記のサンプルコードを参考にして、ゲーム内での使用方法を練習してみてください。

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Menu



技術/知識(実装例)

2Dおはじきゲーム(発展編)

2D強制横スクロールアクション(発展編)

3Dダイビングアクション(発展編)

2Dタップシューティング(拡張編)

レースゲーム(抜粋)

2D放置ゲーム(発展編)

3Dレールガンシューティング(応用編)

3D脱出ゲーム(抜粋)

2Dリアルタイムストラテジー

2Dトップビューアドベンチャー(宴アセット使用)

3Dタップアクション(NavMeshAgent 使用)

2Dトップビューアクション(カエルの為に〜、ボコスカウォーズ風)

VideoPlayer イベント連動の実装例

VideoPlayer リスト内からムービー再生の実装例(発展)

AR 画像付きオブジェクト生成の実装例

AR リスト内から生成の実装例(発展)

private



このサイト内の作品はユニティちゃんライセンス条項の元に提供されています。

管理人/副管理人のみ編集できます