【Unity】ランダムにアイテムをドロップするには

Unity

ランダムにアイテムをドロップしたいけど、どうするかについて書いていこうと思います。

パッと思いついたのが生成したいTransformの場所に空のGameObjectを複数設置しておいて

その中から何個かランダムで選んでその子要素としてInstantiateすることでドロップするというものです。

ランダムに選ぶにはどうするか

//イメージ
//簡略して書いてあるのでもちろんこのままでは動きません
public GameObject[] obj_parent;
public GameObject DropItem;
void Start(){
int random = Random.Range (0, obj.Length);
Instantiate(DropItem ,obj_parent[random])
}

複数のオブジェクトからひとつを選ぶのであれば、ランダムに変数を生成して配列に入れたオブジェクトのn番目を選ぶ上のようなやり方で大丈夫ですが

今回は複数選びたいので、上の方法を繰り返すやり方だと被ってしまいます。被ったらもう一回ランダム変数を生成するのもありですが、オススメのやり方があるので紹介します。

いわゆるランダムソートです。リストをランダムにシャッフルして前から任意の数を取得するものです。

スクリプト

RandomDropScript

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RandomDropScript : MonoBehaviour
{
    public GameObject DropPoint_parent;
    private List<GameObject> d_list = new List<GameObject>();
    private GameObject DropItem;
    //Inspectorでドロップしたい個数を入力。
    [SerializeField]
    private int num_Item;
    private void Start()
    {
       //Resourcesフォルダに自分の生成したいアイテムのprefabをおいて取得
        DropItem = Resources.Load<GameObject>("ArtiFact_Item");
        foreach (Transform child in DropPoint_parent.transform) {
            GameObject obj = child.gameObject;
            Debug.Log(obj);
            d_list.Add(obj);
        }
        Debug.Log(d_list);
     //
        for (int x = 0; x < d_list.Count; x++)
        {
            GameObject tmp = d_list[x];
            int randomIndex = Random.Range(x, d_list.Count);
            d_list[x] = d_list[randomIndex];
            d_list[randomIndex] = tmp;
        }
        
        for (int y = 0; y < num_Item; y++)
        {
            Instantiate(DropItem, d_list[y].transform);
        }
    }
}

使い方

DropItem = Resources.Load<GameObject>("ArtiFact_Item");

Resources フォルダにドロップしたいアイテムを入れます。そしてアイテム名を()の中に設定します。

名前はなんでも大丈夫ですが自分がアイテムをドロップしたい箇所にゲームオブジェクト(上ではDropPointとしてます)を設置します。上のものは14箇所

それを空のゲームオブジェクト(上ではDropPointsとしてます)の子要素に入れます。

親要素をInspectorにいれます!おしまい!

解説

foreach (Transform child in DropPoint_parent.transform) {
            GameObject obj = child.gameObject;
            Debug.Log(obj);
            d_list.Add(obj);
        }

foreach文はfor文と役割は大差ないですがfor文だと下のような感じ、子オブジェクトをリストに追加してます。

for( int i=0 ; i < DropPoint_parentの子要素数; i++){ 
  GameObject obj = transform.GetChild(i).gameObject;
   d_list.Add(obj);
}

シャッフル

for (int x = 0; x < d_list.Count; x++)
        {
            GameObject tmp = d_list[x];
            int randomIndex = Random.Range(x, d_list.Count);
            d_list[x] = d_list[randomIndex];
            d_list[randomIndex] = tmp;
        }

リストに入っているオブジェクトの数だけ入れ替えが行われます。

GameObject tmp = d_list[x];

tmpに代入して値を保持

int randomIndex = Random.Range(x, d_list.Count);

乱数生成

d_list[x] = d_list[randomIndex];

ここがキモです。d_list[x]の値を(生成した乱数)番目のオブジェクトに変更

d_list[randomIndex] = tmp;

保持していたtmp(最初のd_list[x])の値をd_list[randomIndex]に代入。つまりx番目と(生成した乱数)番目のオブジェクトとの値交換。

これがリストが保持している数の回数行われます。

for (int y = 0; y < num_Item; y++)
        {
            Instantiate(DropItem, d_list[y].transform);
        }

num_Itemで生成したいオブジェクト分、リストの先頭からDropPointをとります。これでおしまいです。