いぬおさんのおもしろ数学実験室

おいしい紅茶でも飲みながら数学、物理、工学、プログラミング、そして読書を楽しみましょう

Unityでコルーチンを使ってみる

 ゲームを作っていて、敵の攻撃やこちらの照準の動きなどは今まで通りで、それとは独立して画面の一部で1秒ごとに1から20までカウントアップしてそのカウントを表示したいとしましょう。よくあるケースです。特別の攻撃で「20秒間しか使えません」みたいな。あるいは10枚、20枚の静止画をアニメーションさせるため順に表示するとき、0.2秒ごとに絵を切り替えるとか。ぼくは今までこれを言わば自作のタイマで解決していました。再利用できるようにちゃんと仕組みをこしらえておけば、まあ不都合無く便利に使えます。しかし、処理の流れが分かりにくくなるなど、何とかならないものか……と思ってはいたのです。

 コルーチンという仕組みがあります。存在自体は知っていましたが、使おうという気がなく、今まで放っておいたものです。しかし今回試してみて……スバラシイ!!!! そこで備忘録を兼ね、ここに基本的な使い方を載せておきます。しつこいようですがサンプルのコードは飾りは一切なし、が初心者にはありがたいのです。ギリギリ、ポイントのみをコードにしておくのが分かりやすい!!

(使用例1)ゲームの進行と並行して1,2,3,……と20まで1秒ごとにカウントアップする

//カウントアップ開始
StartCoroutine(countA());

//--------------
//コルーチンの定義
IEnumerator countA()
{
    for (int i = 0; i < 20; i++)
    {
        Debug.Log("●" + i.ToString());
        yield return new WaitForSeconds(1f);
    }
}

これだけです。countA()をどこかで定義しておけば、好きなところで
StartCoroutine(countA());
を実行するだけでカウントアップが始まります。ここではforループを使っています。while(true)ループにし、条件によってループを抜ける(breakで)ようにすればそれでもできるでしょう。

(使用例2)カウントアップを独立して2つ、行う。片方は0.5秒ごと

//カウントアップ開始
StartCoroutine(countA());
StartCoroutine(countB());

//----------------------
IEnumerator countA()
{
    for (int i = 0; i < 20; i++)
    {
        Debug.Log("●" + i.ToString());
        yield return new WaitForSeconds(1f);//1秒待つ
    }
}
//-----------------------------------------
IEnumerator countB()
{
    for (int i = 0; i < 10; i++)
    {
        Debug.Log("▲" + i.ToString());
        yield return new WaitForSeconds(0.5f);//0.5秒待つ
    }
}

バラバラにカウントアップされていることを確認しましょう。もちろん3つでも4つでも大丈夫。

(使用例3)countA()(1秒ごとに20回)が終わったらcountB()(0.5秒ごとに10回)を実行する

//カウントアップ開始
StartCoroutine(count());

//-----------------------------------------
IEnumerator count()
{
    yield return StartCoroutine(countA());
    yield return StartCoroutine(countB());
}
//-----------------------------------------
IEnumerator countA()
{
    for (int i = 0; i < 20; i++)
    {
        Debug.Log("●" + i.ToString());
        yield return new WaitForSeconds(1f);
    }
}
//-----------------------------------------
IEnumerator countB()
{
    for (int i = 0; i < 10; i++)
    {
        Debug.Log("▲" + i.ToString());
        yield return new WaitForSeconds(0.5f);
    }
}

これも便利です。
yield return StartCoroutine(xxx);
を続けて書けばいくらでも「あれが終わったら次はこれ、その次はこちら、……」とできます。具体的には……このアニメーションに続いてあの動作を、とか、スプラッシュ画面の表示が終わったらステージ1を開始し、ステージ1が終わったらステージ2の開始、とか。例えば時間をチェックすればこういったゲームの進行の管理はできますが(今まではそうしていました)、コルーチンを使った方がずっと楽だと思います。ステージ間に何かを挟むなど、変更も容易です。

 もっと早く使い始めていれば相当、時間の節約ができたと思います。なお、コルーチンはちょっと見るとマルチスレッドみたいな感じですが、違うのだそう。スレッドとしてはひとつでやっているみたいです。調べてみてください。