(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

(:3[kanのメモ帳]


本ブログの運営者kan.kikuchiが個人で開発したゲームです!超可愛い実写猫の戦略的オンラインカードゲーム!PC&スマホ両対応!

Download on the App Store Google Play で手に入れよう

インスタンスを生成して処理ごとに乱数(ランダムな数)を分ける【Unity】【C#】


このエントリーをはてなブックマークに追加


この記事でのバージョン
Unity 2021.1.23f1


はじめに

以前Unityで作ってるゲームで「30%の確率でアイテム取得する」みたいな時に使える

確率を使って何かを判定する方法とちょっとした自作の確率判定用クラスを紹介しました。



しかしこの時はUnityのRandomというStaticなクラスを作っていたため

「インスタンスを生成して処理ごとに乱数を分ける」事が出来ませんでした。



乱数を分ける事が出来ないと、これまた以前紹介した乱数の再現を行う際に

「特定の場所の乱数だけ再現させる」みたいな事が困難になってしまいます。



と言う事で今回はインスタンスを生成して処理ごとに乱数(ランダムな数)を分ける方法

インスタンスを生成して使えるちょっとした自作の確率判定用クラスを紹介です!


ProbabilityCalclator

Unityで乱数を分ける簡単な方法はインスタンス生成可能なC#(.Net)のRandomクラスを使う事です。



インスタンスを生成する以外はUnityのRandomと同じように使えますが、

floatの乱数を取得する事は出来ないため、Unityではちょっと使い勝手が悪いです。

//Randomのインスタンスを作成(10はシード値)
var random = new System.Random(10);

//0~9の中でランダムな値を取得
var randomValue = random.Next(0, 10);


という事でこのC#のRandomを使った自作の確率判定用クラスProbabilityCalclatorです。

なお前回の記事とクラス名同じなのに注意してください。



使い方は簡単、シードを渡してインスタンスを生成し、そのインスタンスを使い判定を行うだけ。

//シードを指定して確率計算用クラスのインスタンス作成(シードが同じな限りはこれ以降の結果は同じ)
var probabilityCalculator = new ProbabilityCalculator(10);

/*シードをランダムにしたい場合の例*/
//var probabilityCalculator = new ProbabilityCalculator(UnityEngine.Random.Range(0, 9999999));


判定用メソッドは確率を指定してboolを取得するDetect(intでもfloatでもOK)、

//10回、50%の確率判定を行う
for (int i = 0; i < 10; i++) {
  Debug.Log(probabilityCalculator.Detect(50));
}
f:id:kan_kikuchi:20211129065321j:plain


配列(Listでも可)を指定してその中の一つをランダムで選ぶDetermine

//10回、配列(Listでも可)から一つをランダムで選ぶ
var array = new string[] {"aaa", "bbb", "ccc"};
for (int i = 0; i < 10; i++) {
  Debug.Log(probabilityCalculator.Determine(array));
}

//可変長引数なので以下のような形でもOK
//Debug.Log(probabilityCalculator.Determine("aaa", "bbb", "ccc));
f:id:kan_kikuchi:20211129070607j:plain


候補とそれが選ばれる重み指定して、その中の一つをランダムで選ぶDetermineがあります。

なお、重みとは高ければ高いほど選ばれやすい数値の事で、

直接的な確率ではないので、必ずしも累計100ちょうどにする必要はありません。

//候補とその重み
var dict = new Dictionary<string, float>() {
  { "あいう", 9.7f}, //9.7 / (9.7 + 25.15 + 58) * 100 ≒ 10.4%の確率で選ばれる
  { "かきく", 25.15f}, //25.15 / (9.7 + 25.15 + 58) * 100 ≒ 27.1%の確率で選ばれる
  { "さしす", 58f}, //58 / (9.7 + 25.15 + 58) * 100 ≒ 62.5%の確率で選ばれる
};

//10回、候補から一つをランダムで選ぶ
for (int i = 0; i < 10; i++) {
  Debug.Log(probabilityCalculator.Determine(dict));
}
f:id:kan_kikuchi:20211129070729j:plain


一応、想定に近い確率になるかのチェックも載せておきます。

//10000回、50%の確率判定を行って結果表示
var trueCount = 0;
for (int i = 0; i < 10000; i++) {
  if (probabilityCalculator.Detect(50)) {
    trueCount++;
  }
}
Debug.Log($"True : {trueCount}回, {trueCount / 100f}%");

    
//10000回、1/3( = 0.3333…)の確率判定を行って結果表示
var array = new string[] {"aaa", "bbb", "ccc"};
var aaaCount = 0;
for (int i = 0; i < 10000; i++) {
  if (probabilityCalculator.Determine(array) == "aaa") {
    aaaCount++;
  }
}
Debug.Log($"array, aaa : {aaaCount}回, {aaaCount / 100f}%");

    
//10000回、10.4%の確率判定を行って結果表示
var dict = new Dictionary<string, float>() {
  { "あいう", 9.7f}, //9.7 / (9.7 + 25.15 + 58) * 100 ≒ 10.4%の確率で選ばれる
  { "かきく", 25.15f}, //25.15 / (9.7 + 25.15 + 58) * 100 ≒ 27.1%の確率で選ばれる
  { "さしす", 58f}, //58 / (9.7 + 25.15 + 58) * 100 ≒ 62.5%の確率で選ばれる
};
var aiuCount = 0;
for (int i = 0; i < 10000; i++) {
  if (probabilityCalculator.Determine(dict) == "あいう") {
    aiuCount++;
  }
}
Debug.Log($"dict, あいう : {aiuCount}回, {aiuCount / 100f}%");
f:id:kan_kikuchi:20211129071319j:plain