UnityのRandomクラスを使った乱数生成【unity random】の基礎と活用例

ゲーム開発

はじめに

Unityでゲームを作るとき、ランダム性は欠かせない要素ではないでしょうか。 キャラクターの動きを変化させたり、敵やアイテムの出現位置を変えたりする場面で役立ちます。 また、ゲームの面白さや意外性を生み出すためにも、乱数生成はとても大事です。 ただ、乱数といっても複雑に考える必要はなく、Unityに標準で備わっているRandomクラスを活用すれば十分です。 ここでは、unity randomとして知られる機能の使い方や実務での利用シーンを、初心者向けにわかりやすく説明していきます。

Randomクラスの基本概念

Unityで乱数を扱うときは、主にUnityEngine.Randomを使います。 ほとんどのゲーム開発シーンで使われる機能なので、プロジェクトを始める初期段階から知っておくと良いでしょう。 C#の標準ライブラリにもSystem.Randomがありますが、UnityのRandomクラスはゲームエンジンに最適化された形で動作します。 そのため、3D空間内のオブジェクト配置やエフェクト演出など、Unityならではの場面で便利に利用できます。 まずは、このRandomクラスで何ができるのか、基本を押さえておきましょう。

ランダム性が生まれる仕組み

乱数とは、見かけ上は予測しづらい値を返す仕組みです。 実際には数式で疑似的に生成されているため、同じシード値を使うと同じ乱数列を再現できるという特徴があります。 UnityEngine.Randomはシステムの時刻などをもとに初期設定が行われており、普段は意識せずとも多様な乱数を取り出せます。 ゲームにおいては、この擬似乱数がキャラクターの行動を変化させたり、攻撃判定をばらつかせたりする際に使われます。 ただ「本物のカオス的な乱数」を必要とする場面は多くないため、Unityの標準機能で十分ことが足りるケースがほとんどです。

実務で使うポイント

実務では、単純に乱数を取得するだけでなく、どうやって結果を管理するかが重要になります。 たとえば、アイテムドロップ率を何%に設定するかや、ランダムに決定される値をどこで使うかなど、設計をはっきりさせておきたいですね。 また、ゲームの進行に合わせてシード値を固定することで、一部の結果を再現可能にするテクニックもあります。 敵の出現パターンを固定しつつ、一部だけを変動させるような設計は、リプレイ性と戦略性を両立するのに便利です。 Randomクラスを使うときは、開発チーム内で「いつ、どこで、どんな乱数を生成するか」を共有しておくと混乱が少なくなります。

Random.Rangeの使い方

Unityでよく使われる関数がRandom.Rangeです。 数値の範囲を指定して、その中から乱数を返すシンプルなメソッドとなっています。 以下のように、float型とint型で挙動が異なるので注意しましょう。 それぞれの場面で活用できるよう、具体例を交えて紹介します。 最初は難しく感じるかもしれませんが、慣れればとても直感的に使えます。

float型の乱数

たとえば、0.0fから1.0fの間で乱数を取りたい場合、 Random.Range (0.0f, 1.0f)を呼び出します。 このとき返される値は0.0f以上1.0f以下で、小数点を含んだ連続的な値が戻ってきます。 シェーダー表現やエフェクトの強度を少し揺らしたい場合など、微妙な調整で役立つでしょう。 また、浮動小数点の乱数は物理演算の処理にも使われることがあります。 例えば、オブジェクトの初期速度をランダムに設定することで、自然なばらつきを表現できます。

int型の乱数

次に、int型の乱数です。 Random.Range (0, 10)のように、整数値の範囲を指定して使う場合が一般的でしょう。 このとき、返される値は下限を含み、上限を含まない形になります。 つまり、Random.Range(0, 10)なら0以上9未満の整数値です。 上限を含まない仕様が意外と混乱の元になるので、たとえば0から9までの値が欲しいなら Random.Range (0, 10)を呼び出すという点に注意してください。

乱数の用途と具体例

乱数はゲームのさまざまな部分に応用できます。 単純なところでは、移動速度や攻撃力のばらつき、あるいは報酬やアイテムドロップ率の設定などが代表例です。 ランダム要素を上手に取り入れると、毎回同じプレイにならないように調整できます。 一方で、あまりにも運に左右される設計をすると、ユーザーがストレスを感じる可能性もあります。 そのため、どこまでランダムにして、どこから安定させるのかを検討することが大事です。

移動速度の変動

キャラクターの移動速度に少しばらつきを持たせると、動きに自然な揺らぎが加わります。 特にNPCなど、大量に配置されるオブジェクトが同じパターンで移動していると単調になります。 Random.Range(3.0f, 5.0f)のように範囲を与えて、移動速度を設定するだけでも見栄えが変わるでしょう。 ただし、複数のNPCが極端に速度差があると、ゲーム体験がばらばらになるかもしれません。 ここも運用しながら、適切な範囲を試してみることが大切ですね。

アイテムドロップ率

敵を倒した際にアイテムが落ちる確率を決める場合、乱数を用いるのが定番です。 たとえば、Random.Range(0.0f, 100.0f)で0から100までのfloat値を取り、そこから何%を境に当たりかハズレかを判定する方法です。 レアアイテムや通常アイテムなど、複数の判定がある場合は、判定の優先順位や重みづけを決めておきましょう。 レアアイテムの確率があまりに低いと不満が出る可能性もあるので、開発段階でテストプレイしながらバランスを取ることになります。 こういった調整が、最終的にはゲーム全体の満足度に影響してきます。

シード値の活用

シード値とは、乱数生成を開始するときの初期値のようなものです。 UnityEngine.Randomは内部的にシード値を管理しており、通常は自動設定されています。 ただ、 Random.InitState (任意の整数)を使うと、手動でシード値を指定することが可能です。 これにより、同じシード値なら毎回同じ乱数系列が得られるようになります。 実験的に結果を安定させたいときや、特定のパターンを再現したいときに便利です。

シード値を固定する意義

乱数が絡む処理をデバッグするとき、毎回結果が変わると原因を特定しにくいことがあります。 そこで、シード値を固定しておけば、何度実行しても全く同じ挙動が再現できます。 たとえば、「このシーンで必ず同じ敵配置が生まれるようにしたい」という場面では、意図したデータを再確認しやすいでしょう。 他にも、開発過程でステージの自動生成を試すときにも役立ちます。 実務では、デバッグ用や特定モード用にシード値を固定するスクリプトを準備しておくことが多いです。

予測可能な乱数の管理

ランダム要素の内容をユーザーに伝えたくない場合、シード値が推測されないようにする考慮も出てきます。 シングルプレイのゲームであれば、そこまで問題にはならないでしょう。 ですが、オンラインの対戦ゲームや協力ゲームでは、乱数結果を悪用されないように設計を工夫することがあります。 複雑な暗号化が必要となる場面は珍しいですが、データの整合性や対戦バランスの維持には気を配りたいですね。 あまり細かい話になりすぎると初心者には難しいので、まずは「シード値で再現性が変わる」という点だけ押さえておくと良いでしょう。

乱数とゲームバランス

ゲーム開発では、面白さを保ちながらプレイヤーに予測不能な体験を与えることが目標となる場合があります。 乱数はその「予測不能」を実現しやすい要素ですが、行き過ぎると運任せになるリスクもあるでしょう。 ここでは、乱数の入れ方をどう調整すれば良いのか、代表的な観点を紹介します。 最初から高度なアルゴリズムを組む必要はありませんが、大まかな考え方を理解するだけでも役に立ちます。 ぜひ、プロトタイプを作りながら調整を繰り返してみてください。

運要素の調整

同じアクションをしているのに結果が大きく変わると、プレイヤーは戸惑うことがあります。 そこで、ランダム値の範囲を狭めたり、確定要素と組み合わせたりすることで調整する手法が一般的です。 例として、武器のダメージを「基礎ダメージ + Random.Range(-5, 5)」のように設定し、最低保障を設けるなどが挙げられます。 大当たりとハズレの振れ幅が大きい場合は、確率を二段階で判定するなどの工夫も考えられます。 特にRPG系のゲームでは、ランダム性がゲーム体験に与える影響が大きいので、チームメンバーとしっかり擦り合わせましょう。

ゲームのリプレイ性

ゲームを何度も遊んでもらいたい場合、乱数は効果的です。 たとえば、ステージをランダム生成して毎回異なるマップに挑む形にすれば、飽きにくい設計になります。 ただし、あまりに無秩序に生成すると、プレイ不可能な地形ができてしまう恐れもあるかもしれません。 そのため、乱数に基づいて一気に生成するのではなく、セクションごとに制限を加えたり、ある程度のテンプレートを用意した上で微調整したりします。 こうすることで、プレイフィールを安定させつつ、新鮮味を与えることが可能です。

多彩なRandom機能

UnityEngine.RandomにはRange以外にも便利な機能があります。 位置や方向、色合いをランダムに取りたい場合に役立つメソッドがいくつか用意されています。 ここを知っておくと、unity randomの幅広い活用が実現しやすくなるでしょう。 とくに3D空間での演出や、色のバリエーションが豊富なゲームでは活躍の場面が多くなります。 どれも難しいものではないので、使い方を確認してみてください。

insideUnitSphereで3D空間に配置

Random.insideUnitSphereを呼び出すと、半径1の球体の内部にランダムな点を取得できます。 例えば、敵を球状に配置したい場合や、一定範囲内にアイテムを散らばらせたいときに便利です。 内部点をそのまま座標としてオブジェクトに割り当てるだけで、多方向にばらついた配置が実現できます。 ただし、全ての方向が均等に分布されるわけではないので、結果を見ながら調整するケースもあるかもしれません。 狙った見た目にならない場合は、補正アルゴリズムを取り入れるなどの工夫も考えましょう。

onUnitSphereでランダム方向

Random.onUnitSphereは、半径1の球の表面上におけるランダムな点を返します。 これは3D空間でのランダムな方向を示すベクトルとしてよく使われるでしょう。 例えば、パーティクルをばらまく方向をまちまちにしたり、弾が360度に飛んでいく演出を作ったりするのに役立ちます。 insideUnitSphereとの違いは、球の表面だけを対象にしている点です。 方向に関わる処理だけで、位置は固定というケースではこちらの方が扱いやすいでしょう。

ColorHSVでカラーバリエーション

**Random.ColorHSV()**を使うと、ランダムな色を簡単に生成できます。 引数を指定すれば、彩度や明度の範囲をコントロールできるため、一定のトーンを保ちつつ色を変えることも可能です。 特に、アイテムの見た目を少しずつ変えてプレイヤーに多様性を感じさせる場面では便利だと感じるでしょう。 強い彩度ばかりの色にならないようにするには、最小・最大の値を調整するなどの工夫が必要です。 色が派手になりすぎるとゲーム全体の雰囲気と合わないこともあるので、適度な範囲設定を心がけたいですね。

実践的なサンプルコード

ここでは、ステージ上に複数のオブジェクトをランダム配置する例を取り上げてみます。 複雑な仕組みではなく、Random.RangeとRandom.insideUnitSphereを組み合わせたシンプルな実装です。 座標指定の範囲を自由に変えられるようにし、ゲームの幅を広げてみましょう。 必ずしもステージ全域に置く必要はなく、一部のエリアに限定して配置する形にも応用できます。 下記のコードはオブジェクトを生成する簡単なイメージです。

using UnityEngine;

public class RandomSpawner : MonoBehaviour
{
    public GameObject spawnPrefab;
    public int spawnCount = 10;
    public float spawnRadius = 5.0f;

    void Start()
    {
        for (int i = 0; i < spawnCount; i++)
        {
            // 中心が(0,0,0)の球体内でランダムに座標を取得
            Vector3 randomPos = Random.insideUnitSphere * spawnRadius;

            // y座標を地面に合わせたいなら、0以上に補正
            randomPos.y = Mathf.Max(randomPos.y, 0.0f);

            // オブジェクトを生成
            Instantiate(spawnPrefab, randomPos, Quaternion.identity);
        }
    }
}

上記では、spawnRadiusの値を増やすほど広範囲にオブジェクトが散らばります。 もし、完全に平面上だけに配置したいなら、y座標を固定するのも一つの手です。 たとえば、randomPos.y = 0.0f;として、X-Z平面上に並べることもできます。 このように、Random機能を少し組み合わせるだけで、意外性のあるマップや配置を簡単に作り出せます。 ゲームジャンルによっては、これを応用してアイテムや敵を発生させるシステムを作ることも多いです。

注意点とよくあるエラー

乱数はどうしても毎回結果が変わるので、思わぬ挙動を起こす場合があります。 中でも、上限や下限の扱いを勘違いしてバグを生むケースが少なくありません。 たとえば、Random.Rangeのint版では「上限が含まれない」という仕様を忘れてしまうと、意図しない値が出ることがあります。 また、Random.insideUnitSphereを使っているときに、座標がマイナス方向へ入ってしまい、オブジェクトが想定外の位置に湧くこともあるでしょう。 エラーというよりは「動かしてみたときに想定と違う場所に配置される」という現象が起こりやすいので、ログを確認して原因を探るのがおすすめです。

Randomクラスを多用しても、ゲームの面白さが自動的に向上するわけではありません。 乱数で生まれる変化と、プレイヤーに与えたい体験とのバランスを意識して設計することが大事です。

また、マルチスレッドやネットワーク通信と絡む場合、どのタイミングでRandom関数が呼ばれているか注意してください。 メインスレッド上の更新順序が原因で、思いがけない値を参照する可能性もあります。 ゲームの規模が大きくなると、乱数の利用箇所が増えて管理が複雑になることもあり得るでしょう。 そういった場合は、Singletonパターンで乱数の管理クラスを用意するなど、設計面を工夫することを検討してみてください。

乱数はあくまで補佐的なツールです。 何かを決める際には、特定の計算ロジックや固定値なども併用して、結果がブレすぎないようにするのが大切ではないでしょうか。

まとめ

ここまで、UnityのRandomクラスを使った乱数生成について、基本的な使い方から実務での応用までを見てきました。 ゲーム開発ではランダム性がよく登場しますが、ただ闇雲に導入すると混乱やバランス崩壊の原因になりがちです。 運用面では、範囲指定やシード値の管理、そしてリプレイ性やゲーム難易度との調整といった要素が重要になります。 そのため、まずは小さなプロトタイプで挙動を確かめながら、段階的に乱数を組み込んでいく方法がおすすめでしょう。 上手に活用すれば、より魅力的なゲーム体験を生み出すことにつながりますので、ぜひ実装に挑戦してみてください。

Unityをマスターしよう

この記事で学んだUnityの知識をさらに伸ばしませんか?
Udemyには、現場ですぐ使えるスキルを身につけられる実践的な講座が揃っています。