Unity自定义Script Finder工具搜索脚本结果不全问题排查
核心问题原因
单个GameObject仅记录首个遍历到的脚本
代码中if (!gameObjectAndScriptNames.Any(x => x.GameObject == script.gameObject))的判断逻辑,导致一个GameObject即便挂载多个自定义脚本,也只会被添加到结果列表一次,且仅保存第一个被遍历到的脚本名称。例如:若某个GameObject同时挂载了GenerateGuid和另一个自定义脚本,它在列表中的脚本名会是后者,搜索Guid时自然不会被匹配到。静态列表未清空复用
gameObjectAndScriptNames是静态集合,每次打开窗口时不会自动清空,旧的搜索数据会残留,可能干扰新的检索结果。未覆盖非激活对象
FindObjectsOfType<MonoBehaviour>()默认仅检索激活状态GameObject上的组件,若挂载GenerateGuid的GameObject处于非激活状态,会被直接忽略。
修复后的代码
using UnityEngine; using UnityEditor; using System.Collections.Generic; using System; using System.Linq; public class GameObjectAndScriptName { public GameObject GameObject; public string ScriptName; public GameObjectAndScriptName(GameObject gameObject, string scriptName) { GameObject = gameObject; ScriptName = scriptName; } } public class ScriptFinder : EditorWindow { ScriptFinder window; List<GameObjectAndScriptName> gameObjectAndScriptNames = new List<GameObjectAndScriptName>(); Vector2 scrollPos; List<string> test = new List<string>(); [MenuItem("EditorUtility/Script Finder")] static void OpenScriptFinder() { var window = (ScriptFinder)EditorWindow.GetWindow(typeof(ScriptFinder), false, "Script Finder"); window.minSize = new Vector2(700, 700); window.maxSize = new Vector2(700, 700); window.RefreshScriptList(); window.Traverse(); } void RefreshScriptList() { // 每次刷新先清空列表 gameObjectAndScriptNames.Clear(); // 查找所有MonoBehaviour,包括非激活对象 MonoBehaviour[] scripts = UnityEngine.Object.FindObjectsOfType<MonoBehaviour>(true); foreach (MonoBehaviour script in scripts) { Type scriptType = script.GetType(); var scope = scriptType.Namespace; // 过滤Unity命名空间下的内置脚本 if (scope == null || !scope.StartsWith("Unity")) { // 每个脚本都单独添加,不再按GameObject去重 gameObjectAndScriptNames.Add(new GameObjectAndScriptName(script.gameObject, scriptType.Name)); } } } void Traverse() { test.Clear(); // 查找所有Transform,包括非激活对象 foreach (Transform t in UnityEngine.Object.FindObjectsOfType<Transform>(true)) { test.Add(t.name); } } string searchString; void OnGUI() { int counter = 0; GUI.color = Color.white; GUILayout.Space(30); // 搜索栏 searchString = GUILayout.TextField(searchString, GUI.skin.FindStyle("ToolbarSeachTextField")); if (GUILayout.Button("", GUI.skin.FindStyle("ToolbarSeachCancelButton"))) { searchString = ""; GUI.FocusControl(null); } GUILayout.Space(15); // 样式设置 GUIStyle TextFieldStyles = new GUIStyle(EditorStyles.textField); GUI.contentColor = Color.white; GUI.color = Color.white; TextFieldStyles.normal.textColor = Color.white; // 统计信息 EditorStyles.label.normal.textColor = Color.yellow; EditorGUILayout.LabelField($" Overall number of GameObjects in Hierarchy: {test.Count}"); EditorGUILayout.Space(10); EditorGUILayout.LabelField(" GameObject Script"); GUILayout.Space(5); EditorStyles.label.normal.textColor = Color.white; // 滚动视图 scrollPos = EditorGUILayout.BeginScrollView(scrollPos, false, false); foreach (GameObjectAndScriptName item in gameObjectAndScriptNames) { EditorGUILayout.BeginHorizontal(); if (!string.IsNullOrEmpty(searchString)) { if (item.ScriptName.Contains(searchString, StringComparison.CurrentCultureIgnoreCase)) { EditorGUIUtility.labelWidth = 25; EditorGUILayout.ObjectField(counter.ToString(), item.GameObject, typeof(GameObject), true); counter++; EditorGUILayout.TextField(item.ScriptName); } } else { EditorGUIUtility.labelWidth = 25; EditorGUILayout.ObjectField(counter.ToString(), item.GameObject, typeof(GameObject), true); EditorGUILayout.TextField(item.ScriptName); counter++; } EditorGUILayout.EndHorizontal(); } GUILayout.EndScrollView(); // 添加刷新按钮,支持手动更新列表 if (GUILayout.Button("Refresh Script List")) { RefreshScriptList(); Traverse(); } } }
关键修复点说明
取消GameObject去重,记录所有脚本实例
移除了按GameObject去重的判断逻辑,每个脚本实例都单独添加到列表中,确保挂载同一脚本的不同GameObject都会被检索到,同时一个GameObject挂载的多个脚本也会分别显示。移除静态成员,每次打开窗口初始化新列表
将gameObjectAndScriptNames和test改为非静态成员,避免旧数据残留;同时添加RefreshScriptList方法,每次打开窗口或手动点击刷新时清空并重建列表。支持检索非激活对象
调用FindObjectsOfType<T>(true)重载方法,传入true参数以包含非激活状态的GameObject及其组件。优化搜索逻辑
将searchString != null改为!string.IsNullOrEmpty(searchString),避免空字符串导致的异常;整理冗余代码,移除无意义的遍历逻辑。
内容的提问来源于stack exchange,提问作者Daniel Lip

