Unity自定义编辑器获取Transform子物体仅显示一级层级问题
Unity编辑器窗口获取子物体层级问题
问题现象
- 原有代码可正常运行,但无论将哪个对象拖拽到
Transform to get childs字段绑定的transform变量上,都会显示场景内所有对象及每个对象的全部层级。 - 需求为仅展示被拖拽对象的所有子层级,而非层级视图中的全部对象。
原有问题代码
using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEditorInternal; using UnityEngine; public class GetChildsEditorWindow : EditorWindow { public Transform transform; List<Transform> allChildren = new List<Transform>(); List<string> names = new List<string>(); Vector2 scrollPos; [MenuItem("Get Childs/Get")] static void Init() { GetChildsEditorWindow window = (GetChildsEditorWindow)EditorWindow.GetWindow(typeof(GetChildsEditorWindow), false, "Get Childs"); window.Show(); } private void OnEnable() { } private void OnGUI() { GUILayout.Space(20); transform = EditorGUILayout.ObjectField("Transform to get childs", transform, typeof(Transform), true) as Transform; if (GUILayout.Button("Start")) { allChildren = new List<Transform>(); ObjectLevel(transform); int count = transform.childCount; for (int i = 0; i < GameObject.FindObjectsOfType<Transform>().Length; i++) { var t = GameObject.FindObjectsOfType<Transform>()[i]; var level = ObjectLevel(t); names.Add(" Level " + level.ToString()); allChildren.Add(t); } } if (allChildren != null && allChildren.Count > 0) { EditorGUILayout.BeginHorizontal(); scrollPos = EditorGUILayout.BeginScrollView(scrollPos, GUILayout.Width(400), GUILayout.Height(400)); for (int i = 0; i < allChildren.Count; i++) { allChildren[i] = EditorGUILayout.ObjectField(names[i], allChildren[i], typeof(Transform), true) as Transform; } EditorGUILayout.EndScrollView(); EditorGUILayout.EndHorizontal(); } } public static int ObjectLevel(Transform current, int level = 0) { if (current.parent) return ObjectLevel(current.parent, ++level); return level; } }
已尝试的修改
最初尝试将遍历全局对象的逻辑替换为直接遍历目标物体一级子物体:
原逻辑代码:
for (int i = 0; i < GameObject.FindObjectsOfType<Transform>().Length; i++) { var t = GameObject.FindObjectsOfType<Transform>()[i];
修改为:
for (int i = 0; i < count; i++) { var t = transform.GetChild(i);
修改后出现新问题:拖拽GameObject时,即使对象存在更深的子层级,也仅会显示第一级子物体,无法展示所有深度层级。
问题原因
- 原逻辑使用
GameObject.FindObjectsOfType<Transform>()获取场景中所有Transform组件,会直接返回全场景所有对象 - 第一次修改仅遍历目标物体的直接子节点(一级子物体),未做递归遍历,无法获取嵌套的深层子物体
- 原有
ObjectLevel方法从当前物体向上递归查找场景根节点计算层级,返回的是物体相对于场景根的全局层级,不是相对于拖拽目标的相对层级,显示数值不符合需求 - 原有代码中变量名
transform与EditorWindow自带的transform属性重名,存在隐式冲突风险 - 每次点击Start按钮时未清空上次查询的列表缓存,会出现数据重复累加的问题
修复方案
新增递归遍历目标物体所有子节点的方法,同时计算子物体相对于目标物体的相对层级,替换原有遍历逻辑即可。
完整修复后代码:
using System.Collections.Generic; using UnityEditor; using UnityEngine; public class GetChildsEditorWindow : EditorWindow { public Transform targetTransform; List<Transform> allChildren = new List<Transform>(); List<string> names = new List<string>(); Vector2 scrollPos; [MenuItem("Get Childs/Get")] static void Init() { GetChildsEditorWindow window = (GetChildsEditorWindow)EditorWindow.GetWindow(typeof(GetChildsEditorWindow), false, "Get Childs"); window.Show(); } private void OnGUI() { GUILayout.Space(20); targetTransform = EditorGUILayout.ObjectField("Transform to get childs", targetTransform, typeof(Transform), true) as Transform; if (GUILayout.Button("Start")) { allChildren.Clear(); names.Clear(); // 从目标物体开始递归遍历所有深层子物体 GetAllChilds(targetTransform, 0); } if (allChildren != null && allChildren.Count > 0) { EditorGUILayout.BeginHorizontal(); scrollPos = EditorGUILayout.BeginScrollView(scrollPos, GUILayout.Width(400), GUILayout.Height(400)); for (int i = 0; i < allChildren.Count; i++) { allChildren[i] = EditorGUILayout.ObjectField(names[i], allChildren[i], typeof(Transform), true) as Transform; } EditorGUILayout.EndScrollView(); EditorGUILayout.EndHorizontal(); } } /// <summary> /// 递归获取所有子物体,同时计算相对层级 /// </summary> /// <param name="parent">当前遍历的父节点</param> /// <param name="relativeLevel">相对于目标根物体的层级,一级子物体为1</param> private void GetAllChilds(Transform parent, int relativeLevel) { if (parent == null) return; int childCount = parent.childCount; for (int i = 0; i < childCount; i++) { Transform child = parent.GetChild(i); allChildren.Add(child); // 增加缩进展示,层级关系更直观 string indent = new string('-', relativeLevel * 2); names.Add($"{indent} Level {relativeLevel + 1}"); // 递归遍历当前子物体的子节点 GetAllChilds(child, relativeLevel + 1); } } }
内容的提问来源于stack exchange,提问作者Daniel Lip
相关产品推荐
相关产品推荐

