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

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

Unityでスケジュールに従って敵キャラを生成する方法

 Unityで、ある瞬間からの時間を測り、2秒後、6秒後、19秒後で特定の動作をさせたいとしましょう。例えば…… Time.realtimeSinceStartup でプログラム起動からの経過時間を測れますが、これの値が2秒、6秒、19秒のときに敵キャラを生成したい、などというケースです。探してみましたが、Unityにはこうした目的にすぐ使えるタイマーのようなものはなさそうです。
 UnityのUpdate()ルーチンは1秒間に何十回もコールされますから、generateEnemy()みたいな敵生成ルーチンを単純にUpdate()内に入れるだけだと無制限にジャンジャン敵が現れてしまいます。ゲームを書く人は何かの方法で適切な数、敵が出てくるように工夫しているのです。これ自体は(面倒だけれど)難しくはありません。ぼくが今まで使っていたのは現在の敵の総数を調べ、その個数に応じて出現確率を調整する、という方法です。Update()がコールされる頻度は状況によって変化しますから、単純に確率だけを調整してもうまくありません。例えばUpdate()1回のコールで1%の確率で敵が1個生成するようにしてしまうと、頻繁にUpdate()がコールされているときは敵がたくさん出現してしまいます。だから頻度に応じて確率を変化させるなどの工夫が必要なのです。個人的にはプログラミングしていて結構鬱陶しい部分で、面倒くさい……。
 そこで! 予め立てたスケジュールに従って敵を生成するために使うクラスを書いてみました。短いですし、コードを読んでいただければ何をしているかはすぐ分かると思います。

public class timer
{
    public List<float> schedule;
    public int pt;
    public float birth;
    public bool check(float t)
    {
        if (this.pt >= this.schedule.Count) { return false; }
        if (t - this.birth >= this.schedule[pt])
        {
            this.pt++;
            return true;
        }
        return false;
    }
    //----------------------------
    //初期化
    public void init(List<float> schedule, float t)
    {
        this.schedule = schedule;
        this.pt = 0;
        this.birth = t;//クラスの生成時刻を入れる
    }
}

スケジュールはリストの形で初期化時に与えます。次の通りです。

    List<float> list = new List<float> { 2f, 6f, 19f };
    timer tm = new timer();//クラスのインスタンス生成
    tm.init(list, 0f);//初期化

これで準備完了です。Update()ルーチン内で以下のようにすればスケジュール通りに generateEnemy() が呼ばれます。なお、stageTime はゲーム開始以来の経過時間です。この例では経過時間が 2, 6, 19 秒で敵が生成されます。

        if (tm.check(stageTime)) 
        {
            generateEnemy();
        }

 プログラミングする人なら、例えば一定時間ごとに何かさせるにはクラスのどこをどう書き換えればよいか、すぐ分かると思います。また初期化時にリストを乱数を使って生成すれば変化もつけられます。

 これでかなり気が楽になりました。最初に少し書きましたが、ゲームでは敵を出現させる、編隊を出現させる、何かのアイテムを出す、……とやらなければいけないことはたくさんあり、その頻度をうまく調節することが必要です。今回はそれらの場面で統一して使えるタイマーを作った、ということです。
 やはり、Unityだから簡単にゲームを書ける……なんて単純な話ではない気がします。あっちにもこっちにも工夫が必要です。勉強しなければならないこともたくさんあります。