【Unity】UnityのRandomを使って重み付き抽選を実装するサンプル

【Unity】UnityのRandomを使って重み付き抽選を実装するサンプル

Unityで乱数を使う場合はRandomクラスを使うのが簡単です。

このクラスの使い方は公式のマニュアルにある『ランダムなゲームプレイ要素の追加』に詳しく書かれているのですが、今回はその中の『異なる発生確率を持ったアイテムを選択する』の節に注目して遊んでみます。

『異なる発生確率を持ったアイテムを選択する』だと長いので、この記事の中では重み付き抽選と呼ぶことにします。

 

環境

macOS 10.13 High Sierra

Unity2018.1.0f2

重み付き抽選とは

サイコロを振った時に出る目は、どれも1/6の確率で現れます。

これとは違い、結果が選択される確率が異なるケースが重み付き抽選です。

分かりやすい例だと宝くじでしょうか。1等は当たる確率がとても低くて、7等までいけば10本に1本の確率で当たるあの感じ。

ソシャゲやってる人ならSSRとSRの確率が違うあの感じを思い出して貰えばいいかも。

モンハンだったら爪はよく出てくるけど逆鱗はあまり出てこない、とか。

これだけ例が出てくるように、重み付き抽選は色々な場面で使われます。

サンプルコードを使ってみる

実はUnityのマニュアルにある『ランダムなゲームプレイ要素の追加』には重み付き抽選のサンプルコードが載っているので、それをアレンジして遊んでみます。

状況設定

モンスターを討伐した時のアイテムドロップを考えます。

以下のアイテムドロップが設定されている時に、アイテムの選択を行い、どのアイテムが選ばれたかコンソールに表示します。

確率 ドロップアイテム
3% 竜の逆鱗
12% 竜のうろこ
25% 竜の爪
60% なし

分かりやすく合計100%にしていますが、実はUnityのサンプルコードだと合計が100でなくてもちゃんと抽選してくれるので便利です。

というのは、確率を全て合計してそれを分母にしているため。大切なのは、各要素が起こりうる確率の相対的な大きさなんです。

スクリプト

上のドロップテーブルを元に抽選を行って、コンソールにアイテム名を表示するスクリプトを作成しました。

あるモンスターが落とすアイテムだけではなく、ゲームに存在するアイテムのDictionaryも作成し、そこから名前を引っ張るようにしています。こうすればドロップアイテムの辞書では、どのアイテムが何%でドロップするかだけ持てば良いですもんね。

この中で、Choose()メソッドはUnityのマニュアルと同じような流れで作成しています。

違う点は、floatの配列の代わりにドロップアイテムのDictionaryから確率の合計を計算していること。今回はDictionaryで確率を持たせているので、そこから合計値を出しています。個人的にDictionaryを良く使うってのも理由のひとつ。

Dictionaryを使わない場合は自分でstructなどを作っておくと便利です。

Random.valueでは0から1までの乱数を返してくれます。1.0fも含まれるので、最後の『return 0』が必要になります。アイテムIDが0の場合は『なし』となるようにしているので、もしこのサンプルを使う場合はあなたのゲームに合わせてチューニングしてくださいな。

 

実行結果

上記のスクリプトを任意のゲームオブジェクトにアタッチしてゲームを実行すると、以下のようにコンソールにメッセージが表示されます。内容はゲームを実行するたびに変化します。

アイテムの入手
アイテムの入手

 

アイテムの入手
アイテムの入手

 

ドロップなしは悲しい
ドロップなしは悲しい

 

流石に逆鱗が出るまでぽちぽち粘るのはキツかったので、以下のようにスクリプトを編集して10000回のドロップを確認できるようにしました。

このスクリプトを実行すると、以下のように10000回のドロップ結果が出てきます。

10000回のドロップ
10000回のドロップ

 

概ね設定値通りの結果ですね。ちゃんと逆鱗も存在していました。

個人的に安心したのが、ちゃんとドロップテーブルのアイテムだけが出てきたこと。ゲーム内のアイテムDictionaryからIDで引っ張る、なんてとこまで実装したので変なアイテムが出ちゃわないか若干不安でした。

実際に使う時には、ゲーム内のアイテム一覧からIDで引くパターンが多いかと思うので、今回はそれも含めて入れています。

あとUnityのサンプルでfloat型でインデックスを返しているのもなんだか気持ち悪いですし、そこも変えました。個人的にインデックスはintで返したい派。

まとめ

今回はUnityのサンプルコードを元に重み付き抽選を実装して遊んでみました。

発生確率が異なる事象はゲームの中でごまんとあるので、多くの人が触れる部分だと思います。

ここではRPGっぽい想定で進めましたが、アクションであれば敵の行動パターンだったりにも使えます。一回自分用に作っておくと使いまわせて便利かも。

アセット作ってます!

CTA-IMAGE

Unityでの開発に役立つアセットを作っています。

3DダンジョンRPGを開発するスピードを200%加速するAssetや、ファンタジーRPGのダンジョンを彩るパーツを取り揃えています。

特に3DダンジョンRPGのゲームを1から作るのは結構時間がかかります。ダンジョン部分の作成はこうしたアセットを使って、開発をブーストさせてみませんか?