親の RectTransform 内に重複を考慮せずに、ランダムに配置した場合は 下図のように重複してしまう場合がある
そのため、重複しないようにランダムに配置するスクリプトを作成した
これにより、上図のように配置することができる
もちろん、配置する数が多すぎると空きスペースが見つからなく
無限ループしてしまうので、その点は注意が必要になる
※ Canvas が Overlay の場合のみ利用できる
使い方
[SerializeField] private RectTransform _root; private List<RectTransform> _list; private void Random() { // ランダムにRectを配置する RectTransformUtility.SetRandomPosition(_root, _list, 50); }
スクリプト
using System.Collections.Generic; using System.Linq; using UnityEngine; public class RectTransformUtility { /// <summary> /// RectTransform を Root の Rect 内部でランダムに配置する /// </summary> public static void SetRandomPosition(RectTransform root, List<RectTransform> transforms, float offset) { var rootRect = new RectPosition(root, offset); var cacheRects = new List<RectPosition>(); foreach (var obj in transforms) { var rectTransform = obj.transform as RectTransform; bool isNotContains; RectPosition rectPosition; Vector2 pos; do { isNotContains = true; pos = rootRect.GetRandomPosition(new Vector2(rectTransform.rect.width, rectTransform.rect.height)); rectTransform.position = pos; rectPosition = new RectPosition(rectTransform, offset); foreach (var cacheRect in cacheRects) { if (cacheRect.Contains(rectPosition)) { isNotContains = false; break; } } } while (!isNotContains); cacheRects.Add(rectPosition); } } private class RectPosition { private readonly Vector3[] _corners = new Vector3[4]; private readonly float _offset; private Vector2 _max; private Vector2 _min; public float xMin => _min[0]; public float xMax => _max[0]; public float yMin => _min[1]; public float yMax => _max[1]; public RectPosition(RectTransform rectTransform, float offset) { rectTransform.GetWorldCorners(_corners); _offset = offset; _max = new Vector2(_corners.Max(c => c.x), _corners.Max(c => c.y)); _min = new Vector2(_corners.Min(c => c.x), _corners.Min(c => c.y)); } /// <summary> /// ランダムな座標を取得 /// </summary> /// <param name="elementSize">Rect のサイズを渡す内部 Pivot は Center想定で半分にする</param> public Vector2 GetRandomPosition(Vector2 elementSize) { var hWidth = elementSize.x / 2f; var hHeight = elementSize.y / 2f; var x = Random.Range(xMin + hWidth, xMax - hWidth); var y = Random.Range(yMin + hHeight, yMax - hHeight); return new Vector2(x, y); } public bool Contains(RectPosition rect) { if (xMin - _offset <= rect.xMin && rect.xMin <= xMax + _offset || xMin - _offset <= rect.xMax && rect.xMax <= xMax + _offset) { if (yMin - _offset <= rect.yMin && rect.yMin <= yMax + _offset || yMin - _offset <= rect.yMax && rect.yMax <= yMax + _offset) { return true; } } return false; } } }