对于资源上MissingScript的清理方案讨论

  Unity工程随着复杂度的提升,常会有Prefab上的脚本丢失的情况,如下图所示:

  

  首先失去关联的脚本,是没有线索找到原来是什么文件的,那么有没有办法批处理将这些MissingScript进行一下清理呢?就我使用的Unity4.6所提供的接口来说,没有非常完美的解决办法,但有一些还算可以用来解决问题的做法。

  方法1:找到所有包含有Missing脚本的Prefab,然后逐个手动删除。

  方法2:通过代码自动批处理解决。

  第一种方法比较笨拙,对于资源量不是很大的工程,可以这样做,查找Missing脚本Prefab的代码如下:

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;

public class ClearMissingScript
{
    [MenuItem("Custom/SelectMissing")]
    static void SelectMissing(MenuCommand command)
    {
        string []guids=AssetDatabase.FindAssets("t:Prefab", ["Assets/PrefabCir"]);

        List<GameObject> selection = new List<GameObject>();

        foreach (string guid in guids)
        {
            string path = AssetDatabase.GUIDToAssetPath(guid);
            GameObject obj=AssetDatabase.LoadAssetAtPath(path, typeof(GameObject)) as GameObject;
            Component[] cs = obj.GetComponents<Component>();

            foreach (Component c in cs)
            {
                if (c == null)
                {
                    selection.Add(obj);
                }
            }
        }

        Selection.objects = selection.ToArray();
    }
}

  上面的脚本会帮你自动选中所有的包含脚本丢失的Prefab,有耐心的话就挨个处理吧...

  第二种方法会智能一下,但是有一些问题,不确定是不是我代码写的有问题哈,代码如下所示:

  

public class CleanUpMissingScripts
{
    [MenuItem("Edit/CleanupMissingScripts &c")]
    public static void CleanupMissingScripts()
    {
        for(int i = 0; i < Selection.gameObjects.Length; ++i)
        {
            var gameObject = Selection.gameObjects[i];

            var components = gameObject.GetComponents<Component>();

            SerializedObject serializedObject = new SerializedObject(gameObject);

            SerializedProperty prop = serializedObject.FindProperty("m_Component");

            int r = 0;

            for(int j = 0; j < components.Length; j++)
            {
                if(components[j] == null)
                {
                    prop.DeleteArrayElementAtIndex(j - r);
                    r++;
                }
            }

            serializedObject.ApplyModifiedProperties();
        }

        AssetDatabase.Refresh();
    }
}

  这个脚本利用SerializedObject和SerializedProperty两个类来进行处理,思路上比较清晰,但是有问题:处理完之后看似清除了所有的Missing脚本,但一运行游戏,这些Missing脚本又回来了,于是换个思路,我们先将处理asset实例化出来,然后对实例化后的GameObject进行处理,再将处理完毕的GameObject写进asset,代码如下所示:

public class MissingScriptsEditor : EditorWindow
{
    private static EditorWindow window;
    private List<GameObject> lstTmp = new List<GameObject>();

    [MenuItem("Custom/MissingScripteEditor")]
    private static void Execute()
    {
        if (window == null)
            window = (MissingScriptsEditor)GetWindow(typeof(MissingScriptsEditor));
        window.Show();
    }

    private void OnGUI()
    {
        GUILayout.BeginVertical("box");
        if (GUILayout.Button("CleanUpSelection", GUILayout.Height(30f)))
        {
            CleanUpSelection();
        }
        GUILayout.EndVertical();
    }

    private void CleanUpSelection()
    {
        var lstSelection = Selection.GetFiltered(typeof(GameObject), SelectionMode.DeepAssets);

        for(int i = 0; i < lstSelection.Length; ++i)
        {
            EditorUtility.DisplayProgressBar("Checking", "逐个分析中,请勿退出!", (float)i / (float)lstSelection.Length);
            var gameObject = lstSelection[i] as GameObject;
            var components = gameObject.GetComponents<Component>();

            for (int j = 0; j < components.Length; j++)
            {
                // 如果组建为null
                if (components[j] == null)
                {
                    CleanUpAsset(gameObject);
                    break;
                }
            }
        }
        EditorUtility.ClearProgressBar();
        AssetDatabase.Refresh();

        foreach (var go in lstTmp)
        {
            GameObject.DestroyImmediate(go);
        }
        lstTmp.Clear();
    }

    private void CleanUpAsset(Object asset)
    {
        GameObject go = PrefabUtility.InstantiatePrefab(asset) as GameObject;

        // 创建一个序列化对象
        SerializedObject serializedObject = new SerializedObject(go);
        // 获取组件列表属性
        SerializedProperty prop = serializedObject.FindProperty("m_Component");

        var components = go.GetComponents<Component>();
        int r = 0;
        for (int j = 0; j < components.Length; j++)
        {
            // 如果组建为null
            if (components[j] == null)
            {
                // 按索引删除
                prop.DeleteArrayElementAtIndex(j - r);
                r++;
            }
        }

        // 应用修改到对象
        serializedObject.ApplyModifiedProperties();

        // 将数据替换到asset
        // PrefabUtility.ReplacePrefab(go, asset);
        PrefabUtility.CreatePrefab(AssetDatabase.GetAssetPath(asset), go);

        go.hideFlags = HideFlags.HideAndDontSave;

        // 删除临时实例化对象
        lstTmp.Add(go);
    }

}

  

  此代码提供了简单的编辑器界面,对于在Project中选中的Prefab进行处理,处理完之后可以很干净的删除所有的MissingScript引用,但是在Ctrl+S或运行游戏的时候会出现一些额外的提示,或者会直接崩掉。但是,重新开启Unity之后就好了,并且问题也解决了。

  所以建议使用这种方法,并且在处理完之后重启一下Unity,然后问题成功解决!

  上面的代码仅供参考,并且此处贴出编辑器处理完之后的报错,希望知道此问题的人能够留言帮我解答一下原因:

  

时间: 2024-10-29 17:50:46

对于资源上MissingScript的清理方案讨论的相关文章

一个轻客户端,多语言支持,去中心化,自动负载,可扩展的实时数据写服务的实现方案讨论

背景 背景是设计一个实时数据接入的模块,负责接收客户端的实时数据写入(如日志流,点击流),数据支持直接下沉到HBase上(后续提供HBase上的查询),或先持久化到Kafka里,方便后续进行一些计算和处理,再下沉到文件系统或做别的输出. 在设计中,对于客户端和服务端有这么些目标. 客户端需要支持多语言(Java,C++),做得尽量轻量级,只要连上服务端的ip:port,以RPC的形式调用简单的write就可以把数据写出去.客户端不承担任何逻辑的处理,服务端的负载均衡对客户端是透明的. 服务端想要

系统中生成编号/单号问题的实现方案讨论

应用场景 场景:对于大多数电商系统或财务系统来说,系统中的单号一般都不是从1开始的自增数字,而是一串有一定意义的字符串序列. 而往往这样的单号是要全局唯一的,不可重复. 那么,每次新增订单记录时,这个单号就要按照指定的规则来生成. 常见的订单号规则是字母前缀+日期+时间+定长的数字,如DD201610201559060001(format:XXYYYYMMDDHHmmssNNNN),PZ16102015000012(format:XXYYMMDDHHNNNNNN) 常见方案... 实现这样的场景

事务(进程 ID )与另一个进程已被死锁在 lock 资源上,且该事务已被选作死锁牺牲品。请重新运行该事务

其实所有的死锁最深层的原因就是一个:资源竞争 表现一:    一个用户A 访问表A(锁住了表A),然后又访问表B    另一个用户B 访问表B(锁住了表B),然后企图访问表A 这时用户A由于用户B已经锁住表B,它必须等待用户B释放表B,才能继续,好了他老人家就只好老老实实在这等了    同样用户B要等用户A释放表A才能继续这就死锁了解决方法:    这种死锁是由于你的程序的BUG产生的,除了调整你的程序的逻辑别无他法    仔细分析你程序的逻辑,    1:尽量避免同时锁定两个资源    2:

fpga 图像缓存方案讨论

fpga存储图像方案讨论 本文不讨论片上ram 以及sram存储,在此进讨论基于sdram存储的情况,在此sdram指 sdr sdram ,ddr sdram , ddr2  sdram ,ddr3  sdram等. (--不用对这些sdram感到惧怕,在quartus中都可以生成他们的IP核,而对用户侧的接口都是avalon接口的--) 1.一般存储方法采用乒乓操作 过程: (1)假设两个bank,当进来第一幅图像的时候,存到第二个bank,然后启动乒乓操作,此时开始向bank1 写数据,读

cts全流程自动化方案讨论

CTS全流程自动化方案讨论 功能愿景 cts全流程自动化.大致包括以下模块: 版本构建 强制OTA升级 自动retry 报告+日志备份并解析 邮件发送 方案痛点 目标 方案 问题等级&痛点 版本构建 目前方案:python库paramiko远程ssh登录详细:win端python脚本paramiko库远程ssh登录Linux编译服务器,将一键编译命令写入一个python文件,然后执行该"一键编译命令"py文件 问题等级:低版本有时候会下载不下来,需要人工干预.自动构建不是问题,

快速进行表空间清理方案的编写和操作

一.查询数据库表空间使用率select total.tablespace_name,round(total.gb, 2) total_gb,round(total.gb, 2) - round(nvl(free.gb, 0), 2) used_gb,round(nvl(free.gb, 0), 2) free_gb,round( 100 ( 1 - nvl( free.gb, 0 ) / total.gb ), 2 ) "USED RATE(%)",round(nvl(free.gb,

并发错误:事务(进程 ID )与另一个进程已被死锁在 lock 资源上,且该事务已被选作死锁牺牲品

这个是并发情况下导致的数据库事务错误,先介绍下背景. 背景 springboot+springmvc+sqlserver+mybatis 一个controller里有五六个接口,这些接口都用到了spring的事务管理,这些接口单个调用的时候都很正常,当我模拟几十个并发请求这些接口的时候,总会有一两次的mybatis的持久化操作会出错,具体错误: nested exception is org.apache.ibatis.exceptions.PersistenceException: ### E

Mac上的软件清理卸载工具

Mac上的软件清理卸载工具 Elimisoft App Uninstaller for Mac是一款Mac上的软件清理卸载工具,这款软件可以帮助大家快速卸载掉那些没用的垃圾软件,为大家快速的腾出储存空间.这款软件清理时不会残留其它的垃圾文件.因为该软件能够完全删除那些软件的剩余文件.这款软件还可以轻松删除各种扫描恶意应用程序,病毒,从而提高您的Mac运行速度. 与其他卸载应用程序不同,Elimisoft App Uninstaller是一种帮助您扫描Mac上所有应用程序和病毒的好方法.您可以选择

asp.net如何实现负载均衡方案讨论

我的目标是我一个人搭建一个负载均衡网站.不接受这是网络部,或者运维,或者系统部的事情,所有事情都是我一个人来完成,包括掏钱,包括将来发展等等,同时也别告诉我有没有意义,just do  it !给我方案,给我方法. 拥有资源:不够可以买,多了可以先闲着. 现在我已经买了5台阿里云服务器,ip地址分别为 ip地址                      名字简称      操作系统       iis服务器     cpu   内存DDR3      机械硬盘 111.13.101.204