当前位置: 首页 > news >正文

【总】Unity Editor

时间:2026.07

版本:Unity 6000.3.19f1


打包前预处理

using UnityEditor; using UnityEditor.Build; using UnityEditor.Build.Reporting; using UnityEngine; public class InitializeBeforeBuild : IPreprocessBuildWithReport { public int callbackOrder => 0; // 执行顺序(数值越小越先执行) public void OnPreprocessBuild(BuildReport report) { // TODO:预处理内容,例如设置项目名称等 PlayerSettings.productName = "MyProject"; // 项目名称 Debug.Log($"Build Product Name set to: {PlayerSettings.productName}"); } }

清空控制台日志

using System; using System.Reflection; using UnityEditor; using UnityEngine; public class MyEditor : Editor { [MenuItem("Tools/Clear Console Log")] public static void ClearConsoleLog() { try { string LogEntries = "UnityEditor.LogEntries"; Assembly assembly = typeof(EditorWindow).Assembly; Type logEntriesType = assembly.GetType(LogEntries); if (logEntriesType != null) { BindingFlags bindingFlags = BindingFlags.Static | BindingFlags.Public; MethodInfo clearMethod = logEntriesType.GetMethod("Clear", bindingFlags); clearMethod?.Invoke(null, null); Debug.Log("控制台日志已成功清空"); } } catch (Exception e) { Debug.LogError($"清空日志失败: {e.Message}"); } } }

查找指定脚本

0

using System.Collections.Generic; using System.Text; using UnityEditor; using UnityEngine; public class MyEditor : EditorWindow { private MonoScript targetScript; private List<GameObject> foundObjects = new List<GameObject>(); private List<string> foundPaths = new List<string>(); private Vector2 scrollPosition; private bool includeInactive = true; private string searchFilter = ""; private bool searchInProgress; [MenuItem("RicKotel/Windows/Finder Appoint Script")] public static void ShowWindow() { GetWindow<MyEditor>("Finder Appoint Script"); } private 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("没有找到匹配的对象"); } } private 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} 个匹配对象")); } private 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.FindObjectsOfTypeAll<GameObject>() : GameObject.FindObjectsByType<GameObject>(FindObjectsInactive.Include, FindObjectsSortMode.InstanceID); foreach (GameObject go in allObjects) { // 跳过预制体资源(只检查场景实例) if (AssetDatabase.Contains(go)) continue; FindScriptInGameObject(go, scriptType); } searchInProgress = false; ShowNotification(new GUIContent($"搜索完成,发现 {foundObjects.Count} 个匹配对象")); } private 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.LoadAssetAtPath<GameObject>(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} 个匹配对象")); } private 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); } } private 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(); } private string GetObjectTypeLabel(GameObject go) { if (PrefabUtility.IsPartOfPrefabInstance(go)) { return "(实例)"; } else if (AssetDatabase.Contains(go)) { return "(预制体)"; } else { return "(场景)"; } } private 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); } } } private void SetParentsActive(GameObject go) { Transform parent = go.transform.parent; while (parent != null) { parent.gameObject.SetActive(true); parent = parent.parent; } } private 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("已复制到剪贴板")); } private void ClearResults() { foundObjects.Clear(); foundPaths.Clear(); } }

查找丢失脚本

using System.Collections.Generic; using System.Text; using UnityEditor; using UnityEngine; public class MyEditor : EditorWindow { private List<GameObject> missingScriptObjects = new List<GameObject>(); private List<string> missingScriptPaths = new List<string>(); private Vector2 scrollPosition; private bool includeInactive = true; private string searchFilter = ""; [MenuItem("RicKotel/Windows/Finder Missing Script")] public static void ShowWindow() { GetWindow<MyEditor>("Finder Missing Script"); } private 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("没有发现丢失脚本"); } } private 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} 个丢失脚本")); } private void CheckCurrentScene() { ClearResults(); GameObject[] allObjects = includeInactive ? Resources.FindObjectsOfTypeAll<GameObject>() : GameObject.FindObjectsByType<GameObject>(FindObjectsInactive.Include, FindObjectsSortMode.InstanceID); foreach (GameObject go in allObjects) { // 跳过预制体资源(只检查场景实例) if (AssetDatabase.Contains(go)) continue; FindMissingScriptsInGameObject(go); } ShowNotification(new GUIContent($"检查完成,发现 {missingScriptObjects.Count} 个丢失脚本")); } private void CheckAllPrefabs() { ClearResults(); string[] prefabGuids = AssetDatabase.FindAssets("t:Prefab"); foreach (string guid in prefabGuids) { string path = AssetDatabase.GUIDToAssetPath(guid); GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path); if (prefab != null) { FindMissingScriptsInGameObject(prefab, path); } } ShowNotification(new GUIContent($"检查完成,发现 {missingScriptObjects.Count} 个丢失脚本")); } private void FindMissingScriptsInGameObject(GameObject go, string assetPath = null) { // 检查当前对象 Component[] components = go.GetComponents<Component>(); 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); } } private 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(); } private 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); } } } private 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(); } private void ClearResults() { missingScriptObjects.Clear(); missingScriptPaths.Clear(); } }

查找丢失网格

using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; public class MyEditor : EditorWindow { private List<GameObject> missingMeshObjects = new List<GameObject>(); private Vector2 scrollPosition; private bool autoSelect = true; private bool showMeshFilters = true; private bool showSkinnedMeshes = true; private bool showPrefabs = true; private bool showSceneObjects = true; private string searchFilter = ""; [MenuItem("RicKotel/Windows/Finder Missing Mesh")] public static void ShowWindow() { var window = GetWindow<MyEditor>("丢失网格查找器"); window.minSize = new Vector2(400, 300); window.RefreshMissingMeshes(); } private void OnGUI() { DrawToolbar(); DrawMainView(); DrawStatusBar(); } private void DrawToolbar() { GUILayout.BeginHorizontal(EditorStyles.toolbar); if (GUILayout.Button("刷新", EditorStyles.toolbarButton)) { RefreshMissingMeshes(); } autoSelect = GUILayout.Toggle(autoSelect, "自动选择", EditorStyles.toolbarButton); GUILayout.FlexibleSpace(); showMeshFilters = GUILayout.Toggle(showMeshFilters, "网格过滤器", EditorStyles.toolbarButton); showSkinnedMeshes = GUILayout.Toggle(showSkinnedMeshes, "蒙皮网格", EditorStyles.toolbarButton); showPrefabs = GUILayout.Toggle(showPrefabs, "Prefabs", EditorStyles.toolbarButton); showSceneObjects = GUILayout.Toggle(showSceneObjects, "场景对象", EditorStyles.toolbarButton); GUILayout.EndHorizontal(); // 搜索框 GUILayout.BeginHorizontal(EditorStyles.toolbar); GUILayout.Label("搜索:", GUILayout.Width(40)); searchFilter = GUILayout.TextField(searchFilter, EditorStyles.toolbarSearchField); GUILayout.EndHorizontal(); } private void DrawMainView() { scrollPosition = GUILayout.BeginScrollView(scrollPosition); var filteredObjects = missingMeshObjects .Where(go => string.IsNullOrEmpty(searchFilter) || go.name.ToLower().Contains(searchFilter.ToLower())) .ToList(); foreach (var obj in filteredObjects) { if (obj == null) continue; // 处理可能已被销毁的对象 bool isPrefab = PrefabUtility.IsPartOfAnyPrefab(obj); if ((isPrefab && !showPrefabs) || (!isPrefab && !showSceneObjects)) continue; GUILayout.BeginHorizontal(); // 显示对象类型图标 GUIContent content = new GUIContent( obj.name, EditorGUIUtility.ObjectContent(obj, obj.GetType()).image); if (GUILayout.Button(content, EditorStyles.label, GUILayout.Height(24))) { Selection.activeGameObject = obj; EditorGUIUtility.PingObject(obj); } GUILayout.FlexibleSpace(); // 显示问题组件 var problems = GetMissingComponents(obj); GUILayout.Label(string.Join(", ", problems), EditorStyles.miniLabel); // 修复按钮 if (GUILayout.Button("修复", EditorStyles.miniButton, GUILayout.Width(50))) { FixMissingMesh(obj); } GUILayout.EndHorizontal(); } GUILayout.EndScrollView(); } private void DrawStatusBar() { GUILayout.BeginHorizontal(EditorStyles.helpBox); GUILayout.Label($"找到 {missingMeshObjects.Count} 个问题对象"); GUILayout.FlexibleSpace(); if (GUILayout.Button("全部选择", EditorStyles.miniButton)) { Selection.objects = missingMeshObjects.Where(go => go != null).ToArray(); } if (GUILayout.Button("全部修复", EditorStyles.miniButton)) { if (EditorUtility.DisplayDialog("确认", "确定要尝试修复所有丢失的网格吗?", "修复", "取消")) { foreach (var obj in missingMeshObjects.Where(go => go != null)) { FixMissingMesh(obj); } RefreshMissingMeshes(); } } GUILayout.EndHorizontal(); } private void RefreshMissingMeshes() { missingMeshObjects.Clear(); // 查找场景中的对象 if (showSceneObjects) { var sceneObjects = Resources.FindObjectsOfTypeAll<GameObject>() .Where(go => go.hideFlags == HideFlags.None && !EditorUtility.IsPersistent(go)); foreach (var go in sceneObjects) { CheckGameObject(go); } } // 查找Prefab中的对象 if (showPrefabs) { var prefabPaths = AssetDatabase.GetAllAssetPaths() .Where(path => path.EndsWith(".prefab")); foreach (var path in prefabPaths) { var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path); if (prefab != null) { CheckGameObject(prefab); } } } // 自动选择第一个对象 if (autoSelect && missingMeshObjects.Count > 0) { Selection.activeGameObject = missingMeshObjects[0]; EditorGUIUtility.PingObject(missingMeshObjects[0]); } } private void CheckGameObject(GameObject go) { bool hasProblem = false; // 检查MeshFilter if (showMeshFilters) { var meshFilter = go.GetComponent<MeshFilter>(); if (meshFilter != null && meshFilter.sharedMesh == null) { hasProblem = true; } } // 检查SkinnedMeshRenderer if (showSkinnedMeshes) { var skinnedMesh = go.GetComponent<SkinnedMeshRenderer>(); if (skinnedMesh != null && skinnedMesh.sharedMesh == null) { hasProblem = true; } } if (hasProblem) { missingMeshObjects.Add(go); } } private List<string> GetMissingComponents(GameObject go) { var problems = new List<string>(); var meshFilter = go.GetComponent<MeshFilter>(); if (meshFilter != null && meshFilter.sharedMesh == null) { problems.Add("MeshFilter丢失网格"); } var skinnedMesh = go.GetComponent<SkinnedMeshRenderer>(); if (skinnedMesh != null && skinnedMesh.sharedMesh == null) { problems.Add("SkinnedMeshRenderer丢失网格"); } return problems; } private void FixMissingMesh(GameObject go) { bool fixedSomething = false; Undo.RecordObject(go, "修复丢失网格"); // 修复MeshFilter var meshFilter = go.GetComponent<MeshFilter>(); if (meshFilter != null && meshFilter.sharedMesh == null) { meshFilter.sharedMesh = GetDefaultMesh(); fixedSomething = true; } // 修复SkinnedMeshRenderer var skinnedMesh = go.GetComponent<SkinnedMeshRenderer>(); if (skinnedMesh != null && skinnedMesh.sharedMesh == null) { skinnedMesh.sharedMesh = GetDefaultMesh(); fixedSomething = true; } if (fixedSomething) { EditorUtility.SetDirty(go); Debug.Log($"已修复 {go.name} 的丢失网格", go); } else { Debug.LogWarning($"{go.name} 没有需要修复的问题", go); } } private Mesh GetDefaultMesh() { // 尝试获取内置立方体网格 var defaultMesh = Resources.GetBuiltinResource<Mesh>("Cube.fbx"); // 如果找不到内置网格,创建一个新网格 if (defaultMesh == null) { Debug.LogWarning("无法找到内置默认网格,将创建一个新网格"); defaultMesh = new Mesh { name = "DefaultMesh" }; } return defaultMesh; } }

统计文件数量

using System.Collections.Generic; using System.IO; using System.Linq; using UnityEditor; using UnityEngine; public class MyEditor : EditorWindow { private Vector2 scrollPosition; private string searchFilter = ""; private string searchFolder = "Assets"; private Dictionary<string, int> fileTypeCounts = new Dictionary<string, int>(); [MenuItem("Tools/统计文件数量")] public static void ShowWindow() { GetWindow<MyEditor>("Finder Appoint Files"); } private void OnGUI() { EditorGUILayout.HelpBox("统计项目中各种类型文件的数量", MessageType.Info); EditorGUILayout.Space(); // 输入要搜索的文件夹路径 EditorGUILayout.BeginHorizontal(); { EditorGUILayout.LabelField("搜索文件夹:", GUILayout.Width(80)); var height = GUILayout.Height(EditorGUIUtility.singleLineHeight); EditorGUILayout.SelectableLabel(searchFolder, EditorStyles.textField, height); HandleDragAndDrop(); // 处理拖拽事件(通过拖拽指定文件夹) SelctionFolder(); // 选择文件夹按钮事件 } EditorGUILayout.EndHorizontal(); // 搜索过滤 EditorGUILayout.BeginHorizontal(); { EditorGUILayout.LabelField("过滤:", GUILayout.Width(40)); searchFilter = EditorGUILayout.TextField(searchFilter); if (GUILayout.Button("刷新统计", GUILayout.Width(80))) { if (string.IsNullOrEmpty(searchFolder)) searchFolder = "Assets"; CountFileTypes(); } } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); // 结果显示 if (fileTypeCounts.Count > 0) { EditorGUILayout.LabelField($"在文件夹【{searchFolder}】中共发现 {fileTypeCounts.Values.Sum()} 个文件,{fileTypeCounts.Count} 种类型:", EditorStyles.boldLabel); scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition); // 按键名排序(升序) var sortedItems = fileTypeCounts.OrderBy(pair => pair.Key); //// 按数量排序(降序) //var sortedItems = fileTypeCounts.OrderByDescending(pair => pair.Value); foreach (var item in sortedItems) { if (!string.IsNullOrEmpty(searchFilter) && !item.Key.ToLower().Contains(searchFilter.ToLower())) { continue; } EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(item.Key, GUILayout.Width(200)); EditorGUILayout.LabelField(item.Value.ToString(), EditorStyles.boldLabel); EditorGUILayout.EndHorizontal(); } EditorGUILayout.EndScrollView(); } else { EditorGUILayout.LabelField("没有找到文件统计数据"); } } private void OnFocus() { CountFileTypes(); } private void HandleDragAndDrop() { Rect dropArea = GUILayoutUtility.GetLastRect(); if (Event.current.type == EventType.DragUpdated && dropArea.Contains(Event.current.mousePosition)) { DragAndDrop.visualMode = DragAndDropVisualMode.Copy; Event.current.Use(); } else if (Event.current.type == EventType.DragPerform && dropArea.Contains(Event.current.mousePosition)) { DragAndDrop.AcceptDrag(); if (DragAndDrop.paths != null && DragAndDrop.paths.Length > 0) { string path = DragAndDrop.paths[0]; if (Directory.Exists(path)) { // 转换为Assets相对路径 if (path.StartsWith(Application.dataPath)) { searchFolder = "Assets" + path.Substring(Application.dataPath.Length); } else { searchFolder = path; } CountFileTypes(); } } Event.current.Use(); } } private void SelctionFolder() { if (GUILayout.Button("选择文件夹", GUILayout.Width(100))) { string folderPath = EditorUtility.OpenFolderPanel("选择文件夹", "Assets", ""); if (!string.IsNullOrEmpty(folderPath)) { // 转换为相对路径 if (folderPath.StartsWith(Application.dataPath)) { searchFolder = "Assets" + folderPath.Substring(Application.dataPath.Length); CountFileTypes(); } } } } private void CountFileTypes() { fileTypeCounts.Clear(); // 获取项目中所有资源路径 string[] allAssetPaths = AssetDatabase.GetAllAssetPaths(); foreach (string path in allAssetPaths) { // 跳过目录和特殊文件 if (path.StartsWith(searchFolder) && !Directory.Exists(path)) { string extension = Path.GetExtension(path).ToLower(); if (string.IsNullOrEmpty(extension)) { extension = "[无扩展名]"; } if (fileTypeCounts.ContainsKey(extension)) { fileTypeCounts[extension]++; } else { fileTypeCounts.Add(extension, 1); } } } // 添加一些Unity特殊类型的统计 CountSpecificType<Texture2D>("Texture2D"); CountSpecificType<Material>("Material"); CountSpecificType<GameObject>("Prefab"); CountSpecificType<Shader>("Shader"); CountSpecificType<MonoScript>("Script"); CountSpecificType<AnimationClip>("AnimationClip"); CountSpecificType<AudioClip>("AudioClip"); } private void CountSpecificType<T>(string typeName) where T : Object { string filter = $"t:{typeof(T).Name}"; string[] searchInFolders = new string[] { searchFolder }; string[] guids = AssetDatabase.FindAssets(filter, searchInFolders); if (guids.Length > 0) // 数量为0的文件类型不统计数量 fileTypeCounts[$"[{typeName}]"] = guids.Length; } }
http://www.jsqmd.com/news/1220580/

相关文章:

  • 基于HarmonyOS的AI通勤路线对比应用——从对齐到评估的全流程技术实践
  • Bloom Docker部署教程:3步搭建可扩展的API缓存服务
  • 每日安全情报报告 · 2026-07-19
  • 吉安防水修缮优选|筑宅安99.5高分五星品牌,专治梅雨季各类漏水难题 - 筑宅安
  • Continue + VS Code自动化编程方案框架
  • 企业数据管理五大隐性人力成本,AI自动化重塑数字化办公效率
  • 2026连云港市里卫生间漏水、阳台漏水、楼顶漏水、地下室渗水、阳光房漏水哪家防水公司做的好! 核心靠谱公司推荐 - 吉林同城获客
  • 如何下载视频号的视频?官方与第三方方法有哪些,合规风险一并说 - 科技热点发布
  • K8s Pod Pending 逐层排查:从 FailedScheduling 到 PVC StorageClass 不存在的实战记录
  • HarmonyOS7 渐变样式菜单:用 linearGradient 做好视觉菜单
  • 去中心化 AI 推理性能基准框架:统一的延迟、吞吐与成本度量标准设计
  • 生产级无人机强化学习环境配置实战指南
  • flutter_percent_indicator完全指南:打造精美进度指示器的终极方案
  • 如何为你的编辑器定制PowerShellEditorServices:高级配置与调优技巧
  • 豆包如何去水印有哪些方式?实测几款手机电脑在线都能用的工具 - 科技热点发布
  • 重磅公告|卡地亚2026官方服务热线升级|全国统一官方售后通道、官方地址更新 - 卡地亚中国服务中心
  • 2026中山家里卫生间漏水、阳台漏水、楼顶漏水、地下室渗水、阳光房漏水核心靠谱防水公司测评推荐 - 吉林同城获客
  • 拒绝套路!中山黄金回收避坑指南,这6家店报价透明,支持免费上门! - 新芸鼎珠宝首饰
  • cpu_rec实战:从零开始构建自定义CPU架构语料库
  • HarmonyOS 6.1 原子化服务变现实战:从0到1靠元服务赚第一块钱
  • 上海万国中国官方售后服务网点|官方服务电话及地址权威公示(2026年7月最新) - 万国中国服务中心
  • Solana 程序性能优化清单:Compute Unit 审计、账户预取与指令级微优化的系统方法
  • 【AI数字人直播归因分析权威报告】:基于127场真实直播、4.2亿条行为数据的因果推断结论
  • HarmonyOS7 消息徽标展示页实战:Badge 不只是会用,还要用得顺手
  • Invoicely:简单高效的开源发票生成器,让专业发票制作仅需几分钟
  • Python循环控制:while/continue/break原理与应用
  • 2026最新!百达翡丽全国官方售后网点核验报告出炉,超60家正规服务门店详细地址公布 - 百达翡丽中国服务中心
  • 3分钟掌握payload-dumper-go:高效的Android OTA解包利器
  • 西安黄金上门回收实地避坑测评!6 家临街实体门店大盘计价无任何隐形扣费 - 不晚生活号
  • Rapid SCADA项目快速上手:10分钟完成第一个工业监控项目