ゲームオブジェクトの作成および削除
名前空間

コルーチン

関数を呼び出すと戻り値を返す前に実行完了されます。すなわち関数で行なわれるアクションはひとつのフレームで行なわれるということを意味し、関数呼び出しはプロシージャルアニメーションを含めたり、時間の経過を伴う一連のイベントには使用できません。例えば、オブジェクトのアルファ(透明度)が徐々に減少し続けて完全に透明になるまで場面を想定したとします。

void Fade() {
    for (float f = 1f; f >= 0; f -= 0.1f) {
        Color c = renderer.material.color;
        c.a = f;
        renderer.material.color = c;
    }
}

上記のままでは、Fade 関数が望むような効果が得られません。フェードが視覚的に分かるようにするためには、アルファは数フレームに渡り、レンダリングされる中間的な値に変化したうえで、減少していく必要があります。しかし、上記の関数は一つのフレームでのみ実行されます。間のフレームは視覚的に分からず、オブジェクトは瞬間的に透明になります。

Update 関数にコードを追加することでも、フレームごとにフェードすることは可能です。しかし、このようなタスクでは通常コルーチンを使用すると便利です。

コルーチンとは実行を停止して Unity へ制御を戻し、停止したところから次のフレームで実行を継続することができる関数です。C# でコルーチンは次のように宣言します。

IEnumerator Fade() {
    for (float f = 1f; f >= 0; f -= 0.1f) {
        Color c = renderer.material.color;
        c.a = f;
        renderer.material.color = c;
        yield return null;
    }
}

要するに、これは IEnumerator 型を戻り値として yield return ステートメントをボディ部分に含める、という関数の宣言です。yield return の行が実行を停止して次のフレームから実行を継続する場所です。コルーチンを実行するには StartCoroutine 関数を使用します:

void Update() {
    if (Input.GetKeyDown("f")) {
        StartCoroutine("Fade");
    }
}

UnityScript ではもう少し簡単です。yield ステートメントを含む関数はすべてコルーチンとして解釈され IEnumerator 戻り型は明示的に宣言する必要がありません:

function Fade() {
    for (var f = 1.0; f >= 0; f -= 0.1) {
        var c = renderer.material.color;
        c.a = f;
        renderer.material.color = c;
        yield;
    }
}

さらに UnityScript でコルーチンを開始する場合、通常の関数と同様に呼び出します。

function Update() {
    if (Input.GetKeyDown("f")) {
        Fade();
    }
}

Fade 関数のループカウンターはコルーチンのライフサイクルを通じて正しい値を保持します。yield の最中に任意の変数またはパラメーターは正しく保持されます。

デフォルトでコルーチンは yield した直後のフレームから再開しますが、遅延してから再開させるには WaitForSeconds 関数を使用します。

IEnumerator Fade() {
    for (float f = 1f; f >= 0; f -= 0.1f) {
        Color c = renderer.material.color;
        c.a = f;
        renderer.material.color = c;
        yield return new WaitForSeconds(.1f);
    }
}

UnityScript では

function Fade() {
    for (var f = 1.0; f >= 0; f -= 0.1) {
        var c = renderer.material.color;
        c.a = f;
        renderer.material.color = c;
        yield WaitForSeconds(0.1);
    }
}

This can be used as a way to spread an effect over a period of time, but it is also a useful optimization. Many tasks in a game need to be carried out periodically and the most obvious way to do this is to include them in the Update function. However, this function will typically be called many times per second. When a task doesn’t need to be repeated quite so frequently, you can put it in a coroutine to get an update regularly but not every single frame. An example of this might be an alarm that warns the player if an enemy is nearby. The code might look something like this:

function ProximityCheck() {
    for (int i = 0; i < enemies.Length; i++) {
        if (Vector3.Distance(transform.position, enemies[i].transform.position) < dangerDistance) {
                return true;
        }
    }
    
    return false;
}

敵が数多くいる場合にこの関数を毎フレーム呼び出しすることで莫大なオーバーヘッドが生じるかもしれません。しかし、コルーチンを使用して 1/10 秒おきに呼び出すことができます。

IEnumerator DoCheck() {
    for(;;) {
        ProximityCheck;
        yield return new WaitForSeconds(.1f);
    }
}

これによりゲームに悪影響を与えずにチェック回数を飛躍的に減少させられます。

注意: MonoBehaviour が無効の場合でも、MonoBehaviour が完全に破棄されない限りは、コルーチンは停止しません。MonoBehaviour.StopCoroutine と MonoBehaviour.StopAllCoroutines を使ってコルーチンを停止することができます。また、MonoBehaviour が破棄されると、コルーチンも停止します。

ゲームオブジェクトの作成および削除
名前空間