Unity Editor 查找丢失脚本工具 时间2026.07版本Unity 6000.3.19f1说明该脚本文件放到Editor文件夹下using UnityEngine; using UnityEditor; using System.Collections.Generic; using System.Text; public class FinderMissingScript : EditorWindow { private ListGameObject missingScriptObjects new ListGameObject(); private Liststring missingScriptPaths new Liststring(); private Vector2 scrollPosition; private bool includeInactive true; private string searchFilter ; [MenuItem(RicKotel/Windows/Finder Missing Script)] public static void ShowWindow() { GetWindowFinderMissingScript(Finder Missing Script); } void OnGUI() { EditorGUILayout.HelpBox(查找并定位带有丢失脚本的对象, MessageType.Info); // 搜索选项 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(); if (GUILayout.Button(检查选定对象)) { CheckSelectedObjects(); } if (GUILayout.Button(检查当前场景)) { CheckCurrentScene(); } if (GUILayout.Button(检查所有预制体)) { CheckAllPrefabs(); } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); // 结果显示 if (missingScriptObjects.Count 0) { EditorGUILayout.LabelField($发现 {missingScriptObjects.Count} 个丢失脚本:, EditorStyles.boldLabel); // 批量操作按钮 EditorGUILayout.BeginHorizontal(); if (GUILayout.Button(选择全部)) { Selection.objects missingScriptObjects.ToArray(); } if (GUILayout.Button(移除选中对象的丢失脚本)) { RemoveMissingScriptsFromSelection(); } if (GUILayout.Button(清除列表)) { missingScriptObjects.Clear(); missingScriptPaths.Clear(); } EditorGUILayout.EndHorizontal(); // 列表显示 scrollPosition EditorGUILayout.BeginScrollView(scrollPosition); for (int i 0; i missingScriptObjects.Count; i) { if (!string.IsNullOrEmpty(searchFilter) !missingScriptPaths[i].ToLower().Contains(searchFilter.ToLower())) { continue; } EditorGUILayout.BeginHorizontal(); if (GUILayout.Button(missingScriptPaths[i], EditorStyles.label)) { SelectObject(missingScriptObjects[i]); } // 显示场景/预制体标记 if (PrefabUtility.IsPartOfPrefabInstance(missingScriptObjects[i])) { GUILayout.Label((Prefab), GUILayout.Width(60)); } else if (AssetDatabase.Contains(missingScriptObjects[i])) { GUILayout.Label((Asset), GUILayout.Width(60)); } else { GUILayout.Label((Scene), GUILayout.Width(60)); } EditorGUILayout.EndHorizontal(); } EditorGUILayout.EndScrollView(); } else { EditorGUILayout.LabelField(没有发现丢失脚本); } } void CheckSelectedObjects() { ClearResults(); GameObject[] selectedObjects Selection.gameObjects; if (selectedObjects.Length 0) { EditorUtility.DisplayDialog(提示, 请先选择场景中的对象, 确定); return; } foreach (GameObject go in selectedObjects) { FindMissingScriptsInGameObject(go); } ShowNotification(new GUIContent($检查完成发现 {missingScriptObjects.Count} 个丢失脚本)); } void CheckCurrentScene() { ClearResults(); GameObject[] allObjects includeInactive ? Resources.FindObjectsOfTypeAllGameObject() : GameObject.FindObjectsByTypeGameObject(FindObjectsInactive.Include, FindObjectsSortMode.InstanceID); foreach (GameObject go in allObjects) { // 跳过预制体资源只检查场景实例 if (AssetDatabase.Contains(go)) continue; FindMissingScriptsInGameObject(go); } ShowNotification(new GUIContent($检查完成发现 {missingScriptObjects.Count} 个丢失脚本)); } void CheckAllPrefabs() { ClearResults(); string[] prefabGuids AssetDatabase.FindAssets(t:Prefab); foreach (string guid in prefabGuids) { string path AssetDatabase.GUIDToAssetPath(guid); GameObject prefab AssetDatabase.LoadAssetAtPathGameObject(path); if (prefab ! null) { FindMissingScriptsInGameObject(prefab, path); } } ShowNotification(new GUIContent($检查完成发现 {missingScriptObjects.Count} 个丢失脚本)); } void FindMissingScriptsInGameObject(GameObject go, string assetPath null) { // 检查当前对象 Component[] components go.GetComponentsComponent(); bool hasMissing false; foreach (Component component in components) { if (component null) { hasMissing true; break; } } if (hasMissing !missingScriptObjects.Contains(go)) { missingScriptObjects.Add(go); missingScriptPaths.Add(GetFullPath(go, assetPath)); } // 检查子对象 foreach (Transform child in go.transform) { FindMissingScriptsInGameObject(child.gameObject, 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(); } void SelectObject(GameObject go) { // 如果是预制体资源在Project窗口选中 if (AssetDatabase.Contains(go)) { EditorUtility.FocusProjectWindow(); Selection.activeObject go; } else // 如果是场景对象在Hierarchy窗口选中 { EditorUtility.FocusProjectWindow(); Selection.activeGameObject go; EditorGUIUtility.PingObject(go); // 如果是预制体实例同时选中预制体资源 if (PrefabUtility.IsPartOfPrefabInstance(go)) { Object prefabRoot PrefabUtility.GetCorrespondingObjectFromSource(go); EditorGUIUtility.PingObject(prefabRoot); } } } void RemoveMissingScriptsFromSelection() { if (missingScriptObjects.Count 0) return; int totalRemoved 0; Undo.RecordObjects(missingScriptObjects.ToArray(), Remove missing scripts); foreach (GameObject go in missingScriptObjects) { // 跳过预制体资源只能在场景实例上移除 if (!AssetDatabase.Contains(go)) { int removed GameObjectUtility.RemoveMonoBehavioursWithMissingScript(go); totalRemoved removed; } } EditorUtility.DisplayDialog(完成, $已移除 {totalRemoved} 个丢失脚本, 确定); ClearResults(); } void ClearResults() { missingScriptObjects.Clear(); missingScriptPaths.Clear(); } }