【Unity】特定の位置から円状にオブジェクトランダム配置

特定のオブジェクトの周りに、オブジェクトをランダム配置させたいという場面に遭遇しました。

今回は、中央にある赤いオブジェクトを起点にし、周囲に適当なオブジェクトを設定する方法について触れます。 f:id:nakahashi_h:20180802223044p:plain

数学的なお話

今回は円状に配置するので、ランダムで設定した座標XとYが指定した円の長さの中に含まれるかどうかを判定します。
半径Rの円の中に含まれるかどうかの判定は、次の公式を元にします。

半径の2乗は、X軸の2乗とY軸の2乗を足した値と同じ。
R2 = X2 + Y2

つまり、半径の2乗以内であれば円の中であると言えます。

実装方法

今回はオブジェクトに近すぎる場所には設定ませんのでドーナツ状になります。

ソース

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class circlecontroller : MonoBehaviour {

    [Header("分布")]
    [SerializeField] Transform CenterPosition;                 // 対象オブジェクト
    [SerializeField] int ArrangementMaxRedius = 1000;         // 配置位置の最大半径
    [SerializeField] int ArrangementMinRedius = 500;         // 配置位置の最小半径
    [SerializeField] int ArrangementHeight = 10;              // 配置位置の高さ


    [Header("個数")]
    [SerializeField] GameObject CreaturePrefab;                 // 対象オブジェクト
    [SerializeField] int CreatureLength = 100;                 // 配置位置の最大


    private System.Random random;                               // 乱数機

    // Use this for initialization
    void Start () {

        GameObject[] CreatureRange = new GameObject[CreatureLength];
        random = new System.Random();

        int x;
        int z;

        double xAbs;
        double zAbs;

        double maxR = Math.Pow(ArrangementMaxRedius, 2);
        double minR = Math.Pow(ArrangementMinRedius, 2);

        for (int i = 0; i < CreatureRange.Length; i++)
        {
            while (CreatureRange[i] == null){
                x = random.Next(-ArrangementMaxRedius, ArrangementMaxRedius);
                z = random.Next(-ArrangementMaxRedius, ArrangementMaxRedius);

                xAbs = Math.Abs(Math.Pow(x, 2));
                zAbs = Math.Abs(Math.Pow(z, 2));

                // 特定の範囲内化確認
                if (maxR > xAbs + zAbs && xAbs + zAbs > minR)
                {
                    GameObject go = Instantiate(
                        CreaturePrefab,             // 個体のオブジェクト
                        (new Vector3(x, ArrangementHeight, z)) + CenterPosition.position,        // 初期座標
                        Quaternion.identity         // 回転位置
                    );
                    CreatureRange[i] = go;
                }
            }
        }

    }
    
    // Update is called once per frame
    void Update () {
        
    }
}

実行例

実行すると次のように、中心のオブジェクトに対して周囲にランダム設定されます。 f:id:nakahashi_h:20180802225412p:plain

今回は、配置位置が整数型ですが小数型(float)にすればもっときめ細かくなります。
また、3軸を指定すれば円に設定することも出来ます。