#if UNITY_EDITOR using UnityEngine; using UnityEditor; using System.Linq; namespace Test_2022.Utils { public class HierarchySorter : EditorWindow { private static bool includeInactive = true; private static bool sortRecursively = false; [MenuItem("Tools/Hierarchy/Sort Immediate Children Only (A-Z)")] private static void SortSelectedChildren() { GameObject[] selectedObjects = Selection.gameObjects; if (selectedObjects.Length == 0) { EditorUtility.DisplayDialog("提示", "请先选择一个父对象!", "确定"); return; } foreach (GameObject parent in selectedObjects) { SortChildren(parent.transform); } } [MenuItem("Tools/Hierarchy/Sort All Descendants (Recursive)")] private static void SortSelectedChildrenRecursive() { GameObject[] selectedObjects = Selection.gameObjects; if (selectedObjects.Length == 0) { EditorUtility.DisplayDialog("提示", "请先选择一个父对象!", "确定"); return; } foreach (GameObject parent in selectedObjects) { SortChildrenRecursive(parent.transform); } } [MenuItem("Tools/Hierarchy/Open Sort Window...")] private static void ShowWindow() { var window = GetWindow("Hierarchy排序工具"); window.Show(); } private void OnGUI() { GUILayout.Label("Hierarchy 排序工具", EditorStyles.boldLabel); GUILayout.Space(10); includeInactive = EditorGUILayout.ToggleLeft(" 包含非激活对象 (Include Inactive)", includeInactive); sortRecursively = EditorGUILayout.ToggleLeft(" 递归排序所有子层级 (Recursive)", sortRecursively); GUILayout.Space(15); string buttonText = sortRecursively ? "排序选中对象及其所有后代" : "仅排序选中对象的直接子级"; if (GUILayout.Button(buttonText, GUILayout.Height(40))) { SortSelectedWithOptions(); } GUILayout.Space(10); EditorGUILayout.HelpBox( sortRecursively ? "模式:递归\n将排序选中对象下的所有层级物体。\n结构会被彻底重新整理。" : "模式:仅直接子级\n只会排序第一层子对象。\n子对象的子对象保持原样(符合您的需求)。", MessageType.Info ); } private static void SortSelectedWithOptions() { GameObject[] selectedObjects = Selection.gameObjects; if (selectedObjects.Length == 0) { EditorUtility.DisplayDialog("提示", "请先选择一个父对象!", "确定"); return; } Undo.RecordObjects(selectedObjects, "Sort Children"); int totalSorted = 0; foreach (GameObject parent in selectedObjects) { if (sortRecursively) { totalSorted += SortChildrenRecursive(parent.transform); } else { totalSorted += SortChildren(parent.transform); } } } private static int SortChildren(Transform parent) { if (parent == null) return 0; var children = new System.Collections.Generic.List(); for (int i = 0; i < parent.childCount; i++) { children.Add(parent.GetChild(i)); } if (!includeInactive) { children = children.Where(c => c.gameObject.activeSelf).ToList(); } if (children.Count <= 1) return 0; var sortedChildren = children.OrderBy(c => c.name).ToList(); bool orderChanged = false; for (int i = 0; i < children.Count; i++) { if (children[i] != sortedChildren[i]) { orderChanged = true; break; } } if (orderChanged) { for (int i = 0; i < sortedChildren.Count; i++) { Undo.SetTransformParent(sortedChildren[i], parent, "Sort Children"); sortedChildren[i].SetSiblingIndex(i); } } return 1; } private static int SortChildrenRecursive(Transform parent) { if (parent == null) return 0; int totalSorted = SortChildren(parent); for (int i = 0; i < parent.childCount; i++) { Transform child = parent.GetChild(i); if (child.childCount > 0) { totalSorted += SortChildrenRecursive(child); } } return totalSorted; } [MenuItem("GameObject/Sort Children Alphabetically", false, 0)] private static void ContextMenuSort() { SortSelectedChildren(); } [MenuItem("GameObject/Sort Children Alphabetically (Recursive)", false, 1)] private static void ContextMenuSortRecursive() { SortSelectedChildrenRecursive(); } } } #endif