うにてぃブログ

UnityやUnreal Engineの記事を書いていきます

【Unity】特定の範囲にランダムでオブジェクトを配置するコンポーネント

f:id:hacchi_man:20200523022730p:plain

範囲や配置するアイテムサイズを指定して、重複しないようにもしくは完全ランダムで配置することが可能なコンポーネントです

重複不可時はどうしても配置できない場合は非表示にします

f:id:hacchi_man:20200523022559p:plain

using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
 
public class RandomPosition2D : MonoBehaviour
{
    [SerializeField]
    private Vector2Int _length;

    [SerializeField]
    private Transform[] _targets;

    [SerializeField]
    private bool _isOverlay;

    [SerializeField]
    private Vector2Int _itemSize;
 
    private void OnValidate()
    {
        for (int i = 0; i < 2; i++)
        {
            if (_length[i] < 0)
                _length[i] = 0;
            if (_itemSize[i] < 0)
                _itemSize[i] = 0;
        }
    }
  
    private void OnDrawGizmosSelected()
    {
        var pos = transform.position;
        var half = new Vector2(_length.x / 2f, _length.y / 2f);
        // 左
        Gizmos.DrawLine(new Vector3(pos.x - half.x, pos.y - half.y, pos.z), new Vector3(pos.x - half.x, pos.y + half.y, pos.z));
        // 右
        Gizmos.DrawLine(new Vector3(pos.x + half.x, pos.y - half.y, pos.z), new Vector3(pos.x + half.x, pos.y + half.y, pos.z));
        // 上
        Gizmos.DrawLine(new Vector3(pos.x - half.x, pos.y + half.y, pos.z), new Vector3(pos.x + half.x, pos.y + half.y, pos.z));
        // 下
        Gizmos.DrawLine(new Vector3(pos.x - half.x, pos.y - half.y, pos.z), new Vector3(pos.x + half.x, pos.y - half.y, pos.z));
    }
 
    private void Awake()
    {
        List<Bounds> end = new List<Bounds>();
        var halfItem = new Vector2(_itemSize.x / 2f, _itemSize.y / 2f);
        var half = new Vector2(_length.x / 2f, _length.y / 2f);
        var pos = transform.position;
        var min = new Vector2(pos.x - half.x + halfItem.x, pos.y - half.y + halfItem.y);
        var max = new Vector2(pos.x + half.x - halfItem.x, pos.y + half.y - halfItem.y);
        foreach (var _target in _targets)
        {
            var bounds = new Bounds(Vector3.zero, Vector3.zero);
            var hit = false;
            int count = 100;
            do
            {
                hit = false;
                pos.x = Random.Range(min.x, max.x);
                pos.y = Random.Range(min.y, max.y);

                bounds.center = pos;
                bounds.size = new Vector3(_itemSize.x, _itemSize.y, 0f);

                foreach (var b in end)
                {
                    if (b.Contains(bounds.min) ||
                        b.Contains(bounds.max) ||
                        b.Contains(new Vector3(bounds.min.x, bounds.max.y, bounds.min.z)) ||
                        b.Contains(new Vector3(bounds.max.x, bounds.min.y, bounds.min.z)))
                        hit = true;
                }
            } while (hit && count-- >= 0 && !_isOverlay);

            if (count < 0)
            {
                _target.gameObject.SetActive(false);
                continue;
            }
            if (!_isOverlay)
                end.Add(bounds);

            _target.position = pos;
        }
    }
}