工程里有时候难免会遇到一些删除了没用的脚本,但是场景中的物体上并没有跟着移除引用,编译后引擎“The associated script can not be loaded(无法加载关联的脚本)”,于是会出现一个MissingScripts的空组件。一般情况下没有影响(除了观感),但是要做成预制体的时候就会因为该预制体或预制体下的某个物体只要有一个无法加载关联脚本,就会报下面的错误(不要问为啥要做“EventSystem”预制体,HAHA):
一个物体丢失还好,但是在物体数量庞大的大型场景内,一个一个手动寻找或者移除是非常浪费时间和精力的。所以我们可以利用Unity 提供给我们的SerializedObject和SerializedProperty 类自己写一个Custom Editor 的删除MissingScripts的编辑器工具。
SerializedObject:序列化对象,和SerializedProperty(序列化属性)是一种用来编辑unity对象的可序列化字段的通用方式。
SerializedProperty:序列化属性,该类通常和SerialedObjec以及Editor类一起使用用于修改属性的内容。
这两个类都同属于UnityEditor命名空间和UnityEditor class下,可以提供通用的方式编辑对象属性,也可以自动处理预制体等。比如我们将要实现的移除丢失脚本功能。
下面上代码:
using UnityEditor;
using UnityEngine;
namespace AFrame
{
public partial class RemoveMissingScriptsEditor
{
[MenuItem("Tools/Remove Missing Scripts")]
public static void RemoveMissingScripts()
{
//获取Hierarchy面板所有物体。
GameObject[] allObjects = Resources.FindObjectsOfTypeAll(typeof(GameObject)) as GameObject[];
int index;
bool isMissing = false;
for (int i = 0; i < allObjects.Length; i++)
{
if (allObjects[i].hideFlags == HideFlags.None)
{
//获取物体的组件
Component[] components = allObjects[i].GetComponents<Component>();
//序列化物体
SerializedObject serializedObject = new SerializedObject(allObjects[i]);
index = 0;
for (int j = 0; j < components.Length; j++)
{
//判断丢失组件
if (components[j] == null)
{
//通过"m_Component"查找丢失脚本物体属性
SerializedProperty prop = serializedObject.FindProperty("m_Component");
isMissing = true;
//删除丢失脚本组件
prop.DeleteArrayElementAtIndex(j - index);
index++;
}
}
//应用修改
serializedObject.ApplyModifiedProperties();
}
}
if (isMissing)
Debug.Log("Scripts with missing have been deleted.");
else
Debug.Log("No scripts are missing.");
}
}
}
参考资料:
https://docs.unity3d.com/ScriptReference/SerializedObject.html
https://docs.unity3d.com/ScriptReference/SerializedProperty.html