Как можно отсортировать объекты в иерархии также после того, как они отфильтрованы в строке поиска? - PullRequest
0 голосов
/ 02 ноября 2018
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, переместите все их наверх даже при фильтрации.

1 Ответ

0 голосов
/ 08 ноября 2018

Панель поиска представляет собой фильтр view ; это не влияет на состояние вашей иерархии объектов. SetSiblingIndex ничего не знает о поиске, поэтому он не может переупорядочить вещи там. Он может переупорядочивать только объекты с одним и тем же родителем.

Если у вас действительно есть веская причина изменить иерархию объектов и переместить объекты GameObject на основе результатов поиска, вы можете поместить все выбранные в данный момент объекты в один и тот же контейнерный объект в верхней части иерархии сцены, чтобы они все сначала отображаются в результатах поиска, а затем могут быть переупорядочены относительно друг друга.

gameObj.transform.SetParent(someContainerGameObject.transform);

Или вы можете написать свое собственное окно редактора, которое может искать и отображать в любом порядке, не затрагивая иерархию сцены.

Редактировать: Подробнее о поиске активов:

AssetDatabase может использоваться в коде редактора для поиска по всей библиотеке проекта вместо сцены. Поиск очень быстрый, даже с тысячами активов, поэтому разумно сделать что-то подобное:

AssetDatabase.FindAssets("t:GameObject");

Что даст вам строки guid, которые вы можете превратить в ссылки на объекты, используя AssetDatabase.GUIDToAssetPath () и AssetDatabase.LoadAssetAtPath (). Получив ссылки на GameObject, вы можете проверить каждую из них с помощью метода HasAllComponents.

Если вы хотите внести в них изменения, вы либо: а) обновите свой сценарий, чтобы автоматически выполнять такие действия, как AddComponent, либо б) обернуть весь код в новом окне редактора, в котором перечислены эти объекты для удобного выбора в редактор, или в) вы можете автоматически создать новый выбор с помощью кода.

Объяснение деталей каждого варианта выходит за рамки этого вопроса, но это должно помочь вам начать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...