IwamotoBlog

俺に付いて来い

Unityで出現率、発生率をパーセンテージで調整出来るシステムを実装する

Unityバンザイ!Unity大好きおじさんです。

Unityでゲームを作ってるとランダムにこのイベントを発生させたいとか、ランダムにこのモンスターを出現させたいなどの処理を実装したくなる事があると思われます。またそのような処理を実装する際に、今後のことを考慮して出現率などをUnityEditor上から値を設定出来るようにしておくとレベルデザインがとても容易なものになるでしょう。
今回はそのようなシステムの実装をお教えしたいと思います。

実装

テスト用の適当なシーンを作り、空のGameObjectを「MainComponent」 などの名前で作成しましょう。その後、以下のScriptをGameObjectにアタッチしてあげましょう。

Unityエディタ上で出現率、発生率を設定出来るプログラム

これでMainComponent上で適当に数字をこねくり回すと、その数字に伴って出現率が変わるようになりました。

技術的なお話

このようなプログラムを作るとしましょう。スライム、ゴブリン、ドラゴンの三種類のモンスターがいて、それぞれ50%、35%、15%の確率で出現するようにするというプログラムです。

このような出現率を実装する際のアイディアとして雑なものは、0~100までのランダムな数字をRandom.Range (0, 100)などで叩き出して、0~49ならスライム、50~84ならゴブリン……とif文をベタ書きするものですが、流石に数が増えてくるとやってられませんよね。
もう少しスマートなものにしましょう。それぞれの出現率の分だけ対応したインデックスを一つの配列に分布させるというものです。50、35、15をそれぞれ5で割ると10、7、3になりますね。コードで表現すると

void PrintRandomMonsterName () {
    string [] monsterNames = { "スライム", "ゴブリン", "ドラゴン" };
    int [] incidences = { 50, 25, 15 };

    var incidenceDistribution = new List<int> ();

    for (int i = 0, len = monsterNames.Length; i < len; i++) {
        int incidence =  Mathf.RoundToInt (incidencePercent / 5);

        for (int j = 0; j <= incidence; j++) {
            incidenceDistribution.Add (i);
        }
    }

    int rdm = Random.Range (0, incidenceDistribution.Count);
    print (monsterNames [incidenceDistribution [rdm]]);
}

のようになります。
これでincidenceDistributionの中身は割合に対応してインデックスが分布され[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2]のようになり、その要素をランダムに取得する事で出現率の仕組みを実現しました。
しかし、割合をハードコーディングで叩き出しているため、5で割り切れない値などが出たときにあまり正確でない分布になったりします。

それらの解決として各出現率の最大公約数を算出し、それを出現率に除算する事で割合を求めるようにしました。結果、ハードコーディングすることなく最小の要素数で分布リストの生成が可能になり、より正確な出現率システムの実装を実現しました。

おわりに

まあグダグダ述べましたがコピペ、アタッチで使えるので何も考えずに乱用すると良いかと思われます。
もしかしたらより高速で正確な方法があるかもしれませんが、とりあえずはこれがベストだと思います。皆さんもっとUnityの知見をネットにばらまきましょう。