Unity Editor 查找指定脚本工具
时间2026.07版本Unity 6000.3.19f1说明该脚本文件放到Editor文件夹下using System.Collections.Generic; using System.Text; using UnityEditor; using UnityEngine; public class FinderAppointScript : EditorWindow { private MonoScript targetScript; private ListGameObject foundObjects new ListGameObject(); private Liststring foundPaths new Liststring(); private Vector2 scrollPosition; private bool includeInactive true; private string searchFilter ; private bool searchInProgress; [MenuItem(RicKotel/Windows/Finder Appoint Script)] public static void ShowWindow() { GetWindowFinderAppointScript(Finder Appoint Script); } void OnGUI() { EditorGUILayout.HelpBox(查找挂载特定脚本的对象, MessageType.Info); // 目标脚本选择 EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(目标脚本:, GUILayout.Width(60)); targetScript (MonoScript)EditorGUILayout.ObjectField(targetScript, typeof(MonoScript), false); EditorGUILayout.EndHorizontal(); // 搜索选项 EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(过滤对象名字:, GUILayout.Width(85)); searchFilter EditorGUILayout.TextField(, searchFilter); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(包含未激活对象:, GUILayout.Width(100)); includeInactive EditorGUILayout.Toggle(, includeInactive); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); // 功能按钮 EditorGUILayout.BeginHorizontal(); GUI.enabled targetScript ! null !searchInProgress; if (GUILayout.Button(检查选定对象)) { SearchSelectedObjects(); } if (GUILayout.Button(检查当前场景)) { SearchCurrentScene(); } if (GUILayout.Button(检查所有预制体)) { SearchAllPrefabs(); } GUI.enabled true; if (GUILayout.Button(重置)) { searchInProgress false; } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); // 结果显示 if (searchInProgress) { EditorGUILayout.LabelField(正在搜索...); } else if (foundObjects.Count 0) { EditorGUILayout.LabelField($发现 {foundObjects.Count} 个匹配对象:, EditorStyles.boldLabel); // 批量操作按钮 EditorGUILayout.BeginHorizontal(); if (GUILayout.Button(选择全部)) { Selection.objects foundObjects.ToArray(); } if (GUILayout.Button(复制列表)) { CopyResultsToClipboard(); } if (GUILayout.Button(清除结果)) { ClearResults(); } EditorGUILayout.EndHorizontal(); // 列表显示 scrollPosition EditorGUILayout.BeginScrollView(scrollPosition); for (int i 0; i foundObjects.Count; i) { if (!string.IsNullOrEmpty(searchFilter) !foundPaths[i].ToLower().Contains(searchFilter.ToLower())) { continue; } EditorGUILayout.BeginHorizontal(); if (GUILayout.Button(foundPaths[i], EditorStyles.label)) { SelectObject(foundObjects[i]); } // 显示对象类型标记 string typeLabel GetObjectTypeLabel(foundObjects[i]); GUILayout.Label(typeLabel, GUILayout.Width(60)); EditorGUILayout.EndHorizontal(); } EditorGUILayout.EndScrollView(); } else if (targetScript ! null) { EditorGUILayout.LabelField(没有找到匹配的对象); } } void SearchSelectedObjects() { if (targetScript null) { EditorUtility.DisplayDialog(错误, 请先选择目标脚本, 确定); return; } ClearResults(); searchInProgress true; Repaint(); GameObject[] selectedObjects Selection.gameObjects; if (selectedObjects.Length 0) { EditorUtility.DisplayDialog(提示, 请先选择场景中的对象, 确定); searchInProgress false; return; } System.Type scriptType targetScript.GetClass(); if (scriptType null) { EditorUtility.DisplayDialog(错误, 无法获取脚本类型请确保脚本已编译, 确定); searchInProgress false; return; } foreach (GameObject go in selectedObjects) { FindScriptInGameObject(go, scriptType); } searchInProgress false; ShowNotification(new GUIContent($搜索完成发现 {foundObjects.Count} 个匹配对象)); } void SearchCurrentScene() { if (targetScript null) { EditorUtility.DisplayDialog(错误, 请先选择目标脚本, 确定); return; } ClearResults(); searchInProgress true; Repaint(); System.Type scriptType targetScript.GetClass(); if (scriptType null) { EditorUtility.DisplayDialog(错误, 无法获取脚本类型请确保脚本已编译, 确定); searchInProgress false; return; } GameObject[] allObjects includeInactive ? Resources.FindObjectsOfTypeAllGameObject() : GameObject.FindObjectsByTypeGameObject(FindObjectsInactive.Include, FindObjectsSortMode.InstanceID); foreach (GameObject go in allObjects) { // 跳过预制体资源只检查场景实例 if (AssetDatabase.Contains(go)) continue; FindScriptInGameObject(go, scriptType); } searchInProgress false; ShowNotification(new GUIContent($搜索完成发现 {foundObjects.Count} 个匹配对象)); } void SearchAllPrefabs() { if (targetScript null) { EditorUtility.DisplayDialog(错误, 请先选择目标脚本, 确定); return; } ClearResults(); searchInProgress true; Repaint(); System.Type scriptType targetScript.GetClass(); if (scriptType null) { EditorUtility.DisplayDialog(错误, 无法获取脚本类型请确保脚本已编译, 确定); searchInProgress false; return; } string[] prefabGuids AssetDatabase.FindAssets(t:Prefab); int processed 0; foreach (string guid in prefabGuids) { string path AssetDatabase.GUIDToAssetPath(guid); GameObject prefab AssetDatabase.LoadAssetAtPathGameObject(path); if (prefab ! null) { FindScriptInGameObject(prefab, scriptType, path); } processed; if (processed % 50 0) // 每处理50个更新一次UI避免卡死 { EditorUtility.DisplayProgressBar(搜索预制体, $正在处理 {processed}/{prefabGuids.Length}, (float)processed / prefabGuids.Length); Repaint(); } } EditorUtility.ClearProgressBar(); searchInProgress false; ShowNotification(new GUIContent($搜索完成发现 {foundObjects.Count} 个匹配对象)); } void FindScriptInGameObject(GameObject go, System.Type scriptType, string assetPath null) { if (scriptType.BaseType.Name.Contains(Editor)) return; // 检查当前对象 Component component go.GetComponent(scriptType); if (component ! null !foundObjects.Contains(go)) { foundObjects.Add(go); foundPaths.Add(GetFullPath(go, assetPath)); } // 检查子对象 foreach (Transform child in go.transform) { FindScriptInGameObject(child.gameObject, scriptType, assetPath); } } string GetFullPath(GameObject go, string assetPath null) { StringBuilder pathBuilder new StringBuilder(); Transform current go.transform; while (current ! null) { pathBuilder.Insert(0, / current.name); current current.parent; } if (!string.IsNullOrEmpty(assetPath)) { return $[预制体: {assetPath}] {pathBuilder}; } return pathBuilder.ToString(); } string GetObjectTypeLabel(GameObject go) { if (PrefabUtility.IsPartOfPrefabInstance(go)) { return (实例); } else if (AssetDatabase.Contains(go)) { return (预制体); } else { return (场景); } } void SelectObject(GameObject go) { // 如果是预制体资源在Project窗口选中 if (AssetDatabase.Contains(go)) { EditorUtility.FocusProjectWindow(); Selection.activeObject go; EditorGUIUtility.PingObject(go); } else // 如果是场景对象在Hierarchy窗口选中 { // 确保对象是活跃的如果是未激活的父对象的子对象 SetParentsActive(go); Selection.activeGameObject go; EditorGUIUtility.PingObject(go); // 如果是预制体实例同时选中预制体资源 if (PrefabUtility.IsPartOfPrefabInstance(go)) { Object prefabRoot PrefabUtility.GetCorrespondingObjectFromSource(go); EditorGUIUtility.PingObject(prefabRoot); } } } void SetParentsActive(GameObject go) { Transform parent go.transform.parent; while (parent ! null) { parent.gameObject.SetActive(true); parent parent.parent; } } void CopyResultsToClipboard() { StringBuilder sb new StringBuilder(); for (int i 0; i foundObjects.Count; i) { sb.AppendLine(foundPaths[i]); } EditorGUIUtility.systemCopyBuffer sb.ToString(); ShowNotification(new GUIContent(已复制到剪贴板)); } void ClearResults() { foundObjects.Clear(); foundPaths.Clear(); } }