using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
[InitializeOnLoad]
public class CustomHierarchy : MonoBehaviour
{
private static Vector2 offset = new Vector2(0, 2);
public static Color gameObjectFontColor = Color.black;
public static Color prefabOrgFontColor = Color.black;
public static Color prefabModFontColor = Color.white;
public static Color inActiveColor = new Color(0.01f, 0.4f, 0.25f);
public static Color meshRendererColor = Color.yellow;
static CustomHierarchy()
{
EditorApplication.hierarchyWindowItemOnGUI += HandleHierarchyWindowItemOnGUI;
}
private static void HandleHierarchyWindowItemOnGUI(int instanceID, Rect selectionRect)
{
Color fontColor = gameObjectFontColor;
Color backgroundColor = new Color(.76f, .76f, .76f);
FontStyle styleFont = FontStyle.Normal;
var obj = EditorUtility.InstanceIDToObject(instanceID);
GameObject gameObj = EditorUtility.InstanceIDToObject(instanceID) as GameObject;
if (Selection.instanceIDs.Contains(instanceID))
{
backgroundColor = new Color(0.24f, 0.48f, 0.90f);
}
if (obj != null)
{
var prefabType = PrefabUtility.GetPrefabType(obj);
if (gameObj.activeInHierarchy == false)
{
backgroundColor = inActiveColor;
}
if (prefabType == PrefabType.PrefabInstance)
{
styleFont = FontStyle.Bold;
PropertyModification[] prefabMods = PrefabUtility.GetPropertyModifications(obj);
foreach (PropertyModification prefabMod in prefabMods)
{
if (prefabMod.propertyPath.ToString() != "m_Name" && prefabMod.propertyPath.ToString() != "m_LocalPosition.x" && prefabMod.propertyPath.ToString() != "m_LocalPosition.y" && prefabMod.propertyPath.ToString() != "m_LocalPosition.z" && prefabMod.propertyPath.ToString() != "m_LocalRotation.x" && prefabMod.propertyPath.ToString() != "m_LocalRotation.y" && prefabMod.propertyPath.ToString() != "m_LocalRotation.z" && prefabMod.propertyPath.ToString() != "m_LocalRotation.w" && prefabMod.propertyPath.ToString() != "m_RootOrder" && prefabMod.propertyPath.ToString() != "m_IsActive")
{
if (HasAllComponents(gameObj, typeof(MeshRenderer), typeof(BoxCollider)))
{
gameObj.transform.SetSiblingIndex(0);
fontColor = meshRendererColor;
}
else
{
fontColor = prefabModFontColor;
}
break;
}
}
if (fontColor != prefabModFontColor)
{
if (HasAllComponents(gameObj, typeof(MeshRenderer), typeof(BoxCollider)))
{
gameObj.transform.SetSiblingIndex(0);
fontColor = meshRendererColor;
}
else
{
fontColor = prefabOrgFontColor;
}
}
}
else
{
if (HasAllComponents(gameObj, typeof(MeshRenderer), typeof(BoxCollider)))
{
gameObj.transform.SetSiblingIndex(0);
fontColor = meshRendererColor;
}
}
Rect offsetRect = new Rect(selectionRect.position + offset, selectionRect.size);
EditorGUI.DrawRect(selectionRect, backgroundColor);
EditorGUI.LabelField(offsetRect, obj.name, new GUIStyle()
{
normal = new GUIStyleState() { textColor = fontColor },
fontStyle = styleFont
}
);
}
}
public static bool HasAllComponents(GameObject gameObject, params System.Type[] types)
{
for (int i = 0; i < types.Length; i++)
{
if (gameObject.GetComponent(types[i]) == null)
return false;
}
return true;
}
}
我在某些地方做过
gameObj.transform.SetSiblingIndex(0);
它确实在层次结构的主根中工作,只有一个黄色的对象,并且他正在移动到顶部。
但是当我在搜索栏中按名称过滤对象时,例如键入:走廊 有许多对象,但没有一个移到顶部。 我希望在所有添加的位置上所有显示为黄色的对象:
gameObj.transform.SetSiblingIndex(0);
将移至顶部。 因此,例如,如果有30个黄色的对象HasAllComponents即使在过滤时也将它们全部移到顶部。
答案 0 :(得分:1)
搜索栏是 view 过滤器;它对对象层次结构的状态没有影响。 SetSiblingIndex对搜索视图一无所知,因此无法在其中重新排序。它只能对共享同一父对象的对象进行重新排序。
如果您确实有充分的理由修改对象层次结构并根据搜索结果移动游戏对象,则可以将所有当前选择的对象作为场景层次结构顶部附近的同一容器对象的父对象,以便将它们全部在搜索中首先出现,然后可以相对于彼此重新排序。
gameObj.transform.SetParent(someContainerGameObject.transform);
或者您可以编写自己的自定义编辑器窗口,该窗口可以按您想要的任何顺序进行搜索和显示,而完全不影响场景层次。
编辑:有关资产搜索的更多信息:
可以在编辑器代码中使用AssetDatabase而不是Scene搜索整个项目库。即使拥有成千上万的资产,搜索也非常快,因此这样做是合理的:
AssetDatabase.FindAssets("t:GameObject");
这将为您提供Guid字符串,您可以使用AssetDatabase.GUIDToAssetPath()和AssetDatabase.LoadAssetAtPath()将其转换为对象引用。获得GameObject引用后,可以使用HasAllComponents方法检查每个引用。
如果要对其进行更改,则可以a)更新脚本以在需要时自动在其上执行诸如AddComponent之类的操作,或b)将所有代码包装在新的“编辑器”窗口中,该窗口列出了这些对象以便于选择。编辑器,或者c)您可以通过代码自动创建一个新选择。
解释每个选项的详细信息超出了此问题的范围,但这应该可以帮助您入门。