| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- using Sirenix.OdinInspector;
- using System.Collections;
- using System.Collections.Generic;
- using UnityEditor;
- using UnityEngine;
- using System.Linq;
- public class TileChildren : MonoBehaviour
- {
- public Renderer plane;
- public float spacing = 0.1f;
- public float sizeThreshold = 1.5f; // 区分大小件的阈值
- public bool forceSquareLayout = true; // 是否启用正方形平铺
- [ContextMenu("平铺所有部件")]
- [Button("平铺所有部件")]
- public void TileAllMoveItems()
- {
- if (plane == null) return;
- MoveItem[] moveItems = GetComponentsInChildren<MoveItem>();
- if (moveItems.Length == 0) return;
- Vector3 planeCenter = plane.bounds.center;
- Vector3 right = plane.transform.right;
- Vector3 forward = plane.transform.forward;
- Vector3 up = plane.transform.up;
- Quaternion commonRotation = Quaternion.LookRotation(forward, up);
- // --- 收集每个 MoveItem 的整体 Bounds ---
- List<(Transform t, Bounds b)> validItems = new List<(Transform, Bounds)>();
- foreach (var item in moveItems)
- {
- Bounds? bounds = GetCombinedBounds(item.transform);
- if (bounds.HasValue)
- {
- validItems.Add((item.transform, bounds.Value));
- }
- else
- {
- Debug.LogWarning($"物体 {item.name} 没有找到任何 Renderer,无法参与排布");
- }
- }
- if (validItems.Count == 0) return;
- Dictionary<Transform, Vector3> newPositions = new Dictionary<Transform, Vector3>();
- Bounds totalBounds = new Bounds(Vector3.zero, Vector3.zero);
- bool hasBounds = false;
- if (forceSquareLayout)
- {
- // --- 正方形排布 ---
- int count = validItems.Count;
- int cols = Mathf.CeilToInt(Mathf.Sqrt(count));
- int rows = Mathf.CeilToInt(count / (float)cols);
- float currentZ = 0;
- int index = 0;
- for (int r = 0; r < rows; r++)
- {
- float currentX = 0;
- float rowMaxZ = 0;
- for (int c = 0; c < cols; c++)
- {
- if (index >= count) break;
- var (t, b) = validItems[index];
- Vector3 size = b.size;
- Vector3 localPos = right * (currentX + size.x / 2) + forward * (currentZ + size.z / 2);
- newPositions[t] = localPos;
- currentX += size.x + spacing;
- rowMaxZ = Mathf.Max(rowMaxZ, size.z);
- if (!hasBounds) { totalBounds = new Bounds(localPos, Vector3.zero); hasBounds = true; }
- else totalBounds.Encapsulate(localPos);
- index++;
- }
- currentZ += rowMaxZ + spacing;
- }
- }
- else
- {
- // --- 分组平铺模式(大件、小件分开) ---
- List<List<(Transform, Bounds)>> groups = new List<List<(Transform, Bounds)>>()
- {
- new List<(Transform, Bounds)>(), // 大件
- new List<(Transform, Bounds)>() // 小件
- };
- foreach (var (t, b) in validItems)
- {
- float size = b.size.magnitude;
- if (size < sizeThreshold)
- groups[1].Add((t, b));
- else
- groups[0].Add((t, b));
- }
- float groupOffsetZ = 0;
- foreach (var group in groups)
- {
- if (group.Count == 0) continue;
- float currentX = 0;
- float rowMaxZ = 0;
- foreach (var (t, b) in group)
- {
- Vector3 size = b.size;
- Vector3 localPos = right * (currentX + size.x / 2) + forward * (groupOffsetZ + size.z / 2);
- newPositions[t] = localPos;
- currentX += size.x + spacing;
- rowMaxZ = Mathf.Max(rowMaxZ, size.z);
- if (!hasBounds) { totalBounds = new Bounds(localPos, Vector3.zero); hasBounds = true; }
- else totalBounds.Encapsulate(localPos);
- }
- groupOffsetZ += rowMaxZ + spacing;
- }
- }
- // --- 计算整体居中 ---
- Vector3 offsetToCenter = planeCenter - totalBounds.center;
- // --- 应用 ---
- foreach (var kv in newPositions)
- {
- kv.Key.position = kv.Value + offsetToCenter;
- kv.Key.rotation = commonRotation;
- }
- }
- /// <summary>
- /// 获取一个物体及其所有子物体的合并 Bounds
- /// </summary>
- Bounds? GetCombinedBounds(Transform root)
- {
- Renderer[] renderers = root.GetComponentsInChildren<Renderer>();
- if (renderers.Length == 0) return null;
- Bounds combined = renderers[0].bounds;
- for (int i = 1; i < renderers.Length; i++)
- {
- combined.Encapsulate(renderers[i].bounds);
- }
- return combined;
- }
- }
- //#if UNITY_EDITOR
- //[CustomEditor(typeof(TileChildrenByPlane))]
- //public class TileChildrenByPlaneEditor : Editor
- //{
- // public override void OnInspectorGUI()
- // {
- // DrawDefaultInspector();
- // TileChildrenByPlane script = (TileChildrenByPlane)target;
- // if (GUILayout.Button("平铺所有 MoveItem"))
- // {
- // script.TileAllMoveItems();
- // }
- // }
- //}
- //#endif
|