Unity 编辑器-查找所有未被使用的Prefab

这篇具有很好参考价值的文章主要介绍了Unity 编辑器-查找所有未被使用的Prefab。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

需求

接到一个需求,将Res里所有特效相关的prefab检查一下,没有使用的移除。

分析

先拆解一下需求,如下

代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
using UnityEditor;
using Object = UnityEngine.Object;

public class SearchUseing :EditorWindow
{
    
    private Vector2 _pos = Vector2.zero;
    static string[] fileExtensions = { ".cs", ".js", ".txt" };//你查询的文件格式 如 .json 等
    private static List<Object> _objs = new List<Object>();
    private static Dictionary<string, List<string>>  _referenceCache = new Dictionary<string, List<string>>();
    private static Dictionary<string, Object> _allUnUsedDic = new Dictionary<string, Object>();

    private static Dictionary<string, List<string>> _resultDic = new Dictionary<string, List<string>>();
    private  static void ShowWindow()
    {
        var window = (SearchUseing)EditorWindow.GetWindow(typeof(SearchUseing));
        window.titleContent = new GUIContent("Object List");
        window.Show();
    }

    private void OnGUI()
    {
        // 在 EditorWindow 中使用 GUILayout 绘制 UI 元素
        GUILayout.BeginHorizontal();
        GUILayout.Label("选中的Asset列表", EditorStyles.boldLabel);

        if (GUILayout.Button("导出空引用的文件路径"))
        {
            string selectedFolderPath = AssetDatabase.GUIDToAssetPath(Selection.assetGUIDs[0]);
            string folderName = System.IO.Path.GetFileName(selectedFolderPath);
            Output(_resultDic,folderName,true);
        }
        if (GUILayout.Button("导出所有文件及依赖路径"))
        {
            string selectedFolderPath = AssetDatabase.GUIDToAssetPath(Selection.assetGUIDs[0]);
            string folderName = System.IO.Path.GetFileName(selectedFolderPath);
            Output(_resultDic,folderName,false);
        }
        if (GUILayout.Button("移动空引用prefab"))
        {
            MoveAll();
        }
        GUILayout.EndHorizontal();
        Rect rect = new Rect(10, 20, position.width - 20, position.height - 30);
        GUILayout.BeginArea(rect);
        if (_allUnUsedDic is { Count: > 0 })
        {
            _pos = GUILayout.BeginScrollView(_pos);
            foreach (var kv in _resultDic)
            {
                EditorGUILayout.ObjectField(AssetDatabase.LoadMainAssetAtPath(kv.Key), typeof(Object), false);
                foreach (var s in kv.Value)
                {
                    EditorGUILayout.ObjectField(AssetDatabase.LoadMainAssetAtPath(s), typeof(Object), false);
                }
                GUILayout.Space(20);
            }

            GUILayout.EndScrollView();
        }
        GUILayout.EndArea();
        
    }
    [MenuItem("Assets/工具/查找空引用的Prefab")]
    public static void SearchAll()
    {
        _resultDic = new Dictionary<string, List<string>>();
        GetAllDependency();
        foreach (var folderPath in Selection.GetFiltered(typeof(DefaultAsset), SelectionMode.Assets))
        {
            var assetPath = AssetDatabase.GetAssetPath(folderPath);
            var assets = AssetDatabase.FindAssets("t:Prefab", new[] { assetPath });
            foreach (var asset in assets)
            {
                var assetFilePath = AssetDatabase.GUIDToAssetPath(asset);
                _resultDic.Add(assetFilePath,new List<string>());
                ReferenceFilter(assetFilePath);
                _allUnUsedDic.TryAdd(assetFilePath,AssetDatabase.LoadMainAssetAtPath(assetFilePath));
            }
        }

        SearchInAssets(_allUnUsedDic);
        if (_resultDic is { Count: > 0 })
        {
            ShowWindow();
        }
        
    }
    //导出显示结果的txt文件
    private static void Output(Dictionary<string,List<string>> dic,string fileName,bool isNull)
    {
        string filePath = $"temporaryCacheRes/Dic_{fileName}{(isNull ? "1" : "2")}.txt"; // 文件保存路径,可以自己指定

        using (StreamWriter streamWriter = new StreamWriter(filePath))
        {
            foreach (KeyValuePair<string, List<string>> kvp in dic)
            {
                if (isNull&&kvp.Value.Count == 0 || !isNull)
                {
                    streamWriter.WriteLine(kvp.Key); // 写入Key值

                    List<string> items = kvp.Value; 
                    foreach (string item in items)
                    {
                        streamWriter.WriteLine("\t" + item); // 写入Value值,使用tab键缩进
                    }
                    streamWriter.WriteLine("\n" ); 
                }
            }
            AssetDatabase.Refresh();
        }
    }
    private static void GetAllDependency()
    {
        _referenceCache = new Dictionary<string, List<string>>();
        _allUnUsedDic = new Dictionary<string, Object>();
        _objs = new List<Object>();
        var guids = AssetDatabase.FindAssets("");
        foreach (var guid in guids)
        {
            var assetPath = AssetDatabase.GUIDToAssetPath(guid);
            var dependencies = AssetDatabase.GetDependencies(assetPath, false);

            foreach (var dependency in dependencies)
            {
                if (_referenceCache.ContainsKey(dependency))
                {
                    if (!_referenceCache[dependency].Contains(assetPath))
                    {
                        _referenceCache[dependency].Add(assetPath);
                    }
                }
                else
                {
                    _referenceCache[dependency] = new List<string>() { assetPath };
                }
            }
        }
    }
    private static void ReferenceFilter(string path)
    {
        if (_referenceCache.ContainsKey(path))
        {
            foreach (var reference in _referenceCache[path])
            {
                Debug.Log(reference, AssetDatabase.LoadMainAssetAtPath(reference));
                var prefabObj = AssetDatabase.LoadAssetAtPath<Object>(reference);
                if (!_objs.Contains(prefabObj))
                {
                    _objs.Add(prefabObj);
                }
            }

            _resultDic[path] = _referenceCache[path];
        }
        else
        {
            _allUnUsedDic.TryAdd(path,AssetDatabase.LoadMainAssetAtPath(path));
            Debug.LogWarning($"{path}  没有直接引用");
        }

    }
    
    private static void MoveAll()
    {
        foreach (var kv in _allUnUsedDic)
        {
            Debug.Log(kv.Value.name);
            MovePrefabToFolder(kv.Key, kv.Value.name);
            _resultDic.Remove(kv.Key);
        }
        AssetDatabase.Refresh();
    }
    
    //移动到指定路径
    static void MovePrefabToFolder(string path,string prefabName)
    {
        string targetFolderPath = "Assets/Art/Effect/Temp/";
        CreateFolderIfNotExists("Assets/Art/Effect","Temp");
        if (!AssetDatabase.IsValidFolder(targetFolderPath))
        {
            Debug.LogWarning("Invalid folder path: " + targetFolderPath);
            return;
        }

        // 组装新的Prefab路径并移动到指定文件夹
       
        string newPrefabPath = targetFolderPath + prefabName + ".prefab";
        AssetDatabase.MoveAsset(path, newPrefabPath);
        AssetDatabase.SaveAssets();

        Debug.Log("Prefab " + prefabName+ " moved to " + newPrefabPath);
    }
    // public static void SerachInAssets()
    // {
    //     var path = AssetDatabase.GetAssetPath(Selection.activeObject);
    //     var obj = AssetDatabase.LoadMainAssetAtPath(path);
    //     Debug.Log(obj.name);
    //     // SearchInAssets(obj.name,path);
    //     // SearchInTxtFiles(obj.name);
    // }
    //在Assets文件夹中进行搜索
   static void SearchInAssets(Dictionary<string,Object> dic)
    {
        string[] paths = AssetDatabase.GetAllAssetPaths();

        foreach (string path in paths)
        {
            // if (!path.StartsWith("Assets/Game") && !path.StartsWith("Assets/Res/Table/effect"))
            // {
            //     continue;
            // }
            
            if (!path.StartsWith("Assets/Res/Table/effect"))  //写你的筛选条件,比如我这里项目中不会直接使用字符串加载,只会在指定路径下查配表文件
            {
                continue;
            }
            // if (path.StartsWith("Assets/StreamingAssets")||path.StartsWith("Assets/Temp"))
            // {
            //     continue;
            // }

            
            if (AssetDatabase.IsValidFolder(path))
            {
                continue;
            }

            if (IgnoreFile(Path.GetFileName(path)))
            {
                continue;
            }

            if (AssetDatabase.GetMainAssetTypeAtPath(path) == typeof(GameObject))
            {
                //如果是prefab 则不检测(ReferenceFilter已经检测过prefab)
                continue;
            }
            string text = File.ReadAllText(path);
            List<string> tempRemoveList = new List<string>(); 
            foreach (var kv in dic)
            {
                if (_resultDic.ContainsKey(kv.Key))
                {
                    var tempList = _resultDic[kv.Key] ??= new List<string>();
                    var name = kv.Value.name;
                    if (text.Contains(name) && path!=kv.Key )
                    {
                        Debug.Log("Found text in asset: " + path );
                        tempList.Add(path);
                        _resultDic[kv.Key] = tempList;
                        tempRemoveList.Add(kv.Key);
                    }
                }
                else
                {
                    Debug.Log($"当前遍历的路径不在result内,查查为啥");
                }
                
               
            }
            foreach (var s in tempRemoveList)
            {
                _allUnUsedDic.Remove(s);
            }
        }
        Debug.Log("searchend");
    }
 
    //在txt文件中进行搜索
    static void SearchInTxtFiles(string searchText)
    {
        DirectoryInfo directory = new DirectoryInfo(Application.dataPath);

        FileInfo[] files = directory.GetFiles("*.*", SearchOption.AllDirectories).Where(
            f => fileExtensions.Contains(f.Extension.ToLower())).ToArray();

        foreach (FileInfo file in files)
        {
            string text = File.ReadAllText(file.FullName);

            if (text.Contains(searchText))
            {
                Debug.Log("Found text in txt file: " + file.FullName);
            }
        }

        Debug.Log("searchend");
    }

    static bool IgnoreFile(string fileName)
    {
        return fileName == "TextSearchEditor.cs";
    }
    private void OnDestroy()
    {
        _referenceCache.Clear();    
    }
    static void CreateFolderIfNotExists(string path,string name)
    {
        // 检查文件夹是否存在
        if (!AssetDatabase.IsValidFolder(path+"/"+name))
        {
            // 创建文件夹
            AssetDatabase.CreateFolder(path, name);
            AssetDatabase.Refresh();
            Debug.Log("Folder Create at " + path+"/"+name);
        }
        else
        {
            Debug.Log("Folder already exists at " + path);
        }
    }
}

结果
Unity 编辑器-查找所有未被使用的Prefab,# 编辑器拓展,Unity,unity,编辑器,游戏引擎

结果如图所示。每组元素第一个为查找的prefab,之后的是使用了该prefab的预设或配表。
如果一组元素只有一个对象,则这个prefab无引用。
顶部的按钮为指定功能。
PS:使用Prefab名字做的检测,未对同名Prefab做筛选判断文章来源地址https://www.toymoban.com/news/detail-562268.html

到了这里,关于Unity 编辑器-查找所有未被使用的Prefab的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • PyCharm安装使用2023年教程,PyCharm与现流行所有编辑器对比。

    与PyCharm类似的功能和特性的集成开发环境(IDE)和代码编辑器有以下几种: Visual Studio Code(VS Code):由Microsoft开发,VS Code是一个高度可定制和可扩展的代码编辑器。它支持多种编程语言,包括Python,并提供众多扩展以增强功能。 IntelliJ IDEA:PyCharm本身就是基于JetBrains开发的

    2024年02月14日
    浏览(54)
  • 使用VSCode作为Unity的代码编辑器

                    Unity在选择IDE 的时候其实也有很多选择,在 Windows 上我会选择 Visual Studio 或者是 VS Code ,在编程体验上来讲我更喜欢 Visual Studio 。但是在 Mac OS 可能 Visual Studio Mac 版本并非是一个靠谱的选择,它和 Rider 一样都过于笨重,编程体验比较卡顿,于是我还是

    2024年02月08日
    浏览(61)
  • Unity XR新版动作编辑器的使用

    双击 XRI Default Input Actions 打开, XRI Head 为头部跟踪,获取设备头部摄像机与场景摄像机的位置跟踪及更新; XRI LeftHand 为左手的位置跟踪及更新,每帧更新一次,可以添加事件做触感操作,可以根据获取到手的位置信息从而进行操作,不需要经过按键; XRI LeftHand Interaction 是

    2023年04月08日
    浏览(37)
  • 从零开始入门创作游戏——Unity编辑器的使用

    还没找到工作的我继续瞎折腾中,上次搭建环境就花了我3天的时间 从零开始入门创作游戏——Unity3d的环境搭建_默哀d的博客-CSDN博客 接下来是根据油土鳖的视频学习创作的一个小恐龙跳跳跳游戏,直接上手做一次学得更多 https://www.youtube.com/watch?v=UdM9DEys-rI 选择2D核心模板就可

    2024年02月05日
    浏览(64)
  • 【Unity编辑器】使用AssetDatabase创建、删、改、加载资源

    AssetDatabase是Unity编辑器环境下的一种API,主要用于在代码中对项目中的资源进行管理和操作。注意:AssetDatabase的这些方法只能在Unity编辑器环境下运行,不能在构建后的游戏中使用。在游戏运行时,你需要使用其他资源加载方法,如Resources.Load、AssetBundle加载或者Addressables等。

    2024年01月21日
    浏览(48)
  • Unity使用VS编辑器打开项目失败解决办法

    具体表现为:项目文件.sln无法打开,打开脚本文件后无法关联到Unity编辑器 报错信息可能不同,参考出错表现即可 首先去清除有逻辑错误的代码,先注释掉,不然后面可能会无法自动生成解决方案 然后关闭Unity编辑器,找到项目文件夹,删除我列出的文件 重新打开Unity,重

    2024年02月16日
    浏览(72)
  • 记录使用注入的方式为Unity编辑器实现扩展能力

    使用场景 当前项目编辑器中不方便存放或者提交扩展代码 相同的扩展功能需要在多个项目(编辑器)中使用 项目开发中,偶尔临时需要使用一个功能,想随时使用随时卸载 设计思路 使用进程注入,将一个 c/c++ dll 注入到当前运行的unity编辑器中 使用 c/c++ dll 调用 mono 的函数接

    2024年02月15日
    浏览(47)
  • 《Linux操作系统编程》第九章 数据查找和筛选工具 : 了解流编辑器sed和报表生成器awk的简单使用

    🌷🍁 博主 libin9iOak带您 Go to New World.✨🍁 🦄 个人主页——libin9iOak的博客🎐 🐳 《面试题大全》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 🌊 《IDEA开发秘籍》学会IDEA常用操作,工作效率翻倍~💐 🪁🍁 希望本文能够给您带来一定的帮助🌸文章粗浅,敬

    2024年02月12日
    浏览(48)
  • Sprite Editor图片编辑器的使用_unity基础开发教程

    SpriteEditor是Unity引擎中的一个工具,用于创建和编辑2D图片。它提供了一系列功能,可以对图片进行剪裁、切割、翻转、旋转、调整大小等操作,以及设置图片的碰撞检测形状和渲染模式。 SpriteEditor可以帮助开发者将多张图片合并成动画精灵,并为每一帧设置播放时间和循环

    2024年02月01日
    浏览(41)
  • 【Unity】AVPro使用踩坑,编辑器模式使用视频播放正常,打包后视频无法播放的问题

    这个主要是AVPro的坑 一般使用会直接Browse给取文件路径,然后面板上面就能看到视频文件的名字,这个方法在编辑器模式下播放是可以获取到文件的,所以没问题。 但是打包后路径变化,拉取到的地址就不对了。 首先把视频资源改存到StreamingAssets文件夹路径下,然后路径获

    2024年02月16日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包