最近为美术编写一个Unity编辑器的扩展,主要为了减轻美术在修改预制对象时的机械化操作的繁琐和出错。具体实现的几个功能:
1、删除指定组件;
2、复制、粘贴指定的组件;
3、重新关联新的属性;
4、重新保存预制对象;
一、删除指定类型的组件
public static void RemoveComponentHandler(GameObject gameObject, Type componentType) { foreach (var component in gameObject.GetComponents<Component>()) { if (component.GetType() == componentType) { GameObject.DestroyImmediate(component); } } }
二、复制组件(这里实现的是一次仅复制一个某类型的组件)
public static void CopyComponentHandler(Type componentType, GameObject fromGameObject, GameObject toGameObject) { RemoveComponentHandler(toGameObject, componentType); // 查找需要复制的 Component Component needCopyComponent = null; foreach (var component in fromGameObject.GetComponents<Component>()) { if (component.GetType() == componentType) { needCopyComponent = component; break; } } // 进行粘贴操作 // http://answers.unity3d.com/questions/907294/copy-all-components-from-a-gameobject-and-paste-to.html UnityEditorInternal.ComponentUtility.CopyComponent(needCopyComponent); UnityEditorInternal.ComponentUtility.PasteComponentAsNew(toGameObject); }
三、关联新属性
就是遍历指定的GameObject,然后找到它附加的组件,重新设置其值即可。
四、替换预制对象
GameObject activeGameObject = Selection.activeGameObject; if (activeGameObject != null) { // 获取当前的id if (new Regex(@"^d+h$").IsMatch(activeGameObject.name)) { UnityEngine.Object parentObject = null; string strPrefabPath = ""; if (PrefabUtility.GetPrefabType(activeGameObject) == PrefabType.PrefabInstance) { parentObject = EditorUtility.GetPrefabParent(activeGameObject); strPrefabPath = AssetDatabase.GetAssetPath(parentObject); } // 查找id string strId = new Regex(@"h$").Replace(activeGameObject.name, ""); // 第六步 保存预制对象 string strCurrSelectPrefabName = activeGameObject.name; if (strPrefabPath.EndsWith(".prefab")) { // string[] dependPaths = AssetDatabase.GetDependencies(strPrefabPath); GameObject go = GameObject.Instantiate(GameObject.Find(strCurrSelectPrefabName)) as GameObject; PrefabUtility.ReplacePrefab(go, parentObject, ReplacePrefabOptions.ConnectToPrefab); GameObject.DestroyImmediate(activeGameObject); go.name = strCurrSelectPrefabName; AssetDatabase.Refresh(); } Debug.Log("预制对象 " + strCurrSelectPrefabName + " 修改完成。"); } else { Debug.Log("当前选中的GameObject命名不符合要求,格式:id+h。 GameObject Name : " + activeGameObject.name); } }
最核心的几行代码:
1、实例化一个新的GameObject;
2、替换预制对象;
3、销毁老的GameObject;
4、刷新资源;
对于美术的同事来讲,最复杂、麻烦的莫过于重新关联属性,特别是骨骼动画。因为之前没有统一的规范,所以关联哪一段动画实际上是需要一层一层找的,我看着他们找都觉得累,怎么办呢?我想到一个办法,就是通过name查找新的组件,然后重新赋值关联。通过Name查找某个GameObject下的子节点(前提条件是该Name唯一)
public static GameObject FindChildGameObject(GameObject parent, string childName) { if (parent.name == childName) { return parent; } if (parent.transform.childCount < 1) { return null; } GameObject obj = null; for (int i = 0; i < parent.transform.childCount; i++) { GameObject go = parent.transform.GetChild(i).gameObject; obj = FindChildGameObject(go, childName); if (obj != null) { break; } } return obj; }
上面基本上实现了,组件几个常用的方法:
1、添加组件(先复制后粘贴);
2、删除组件;
3、通过名字查找子组件;
4、更新预制对象;