【问题标题】:How can I filter in SetSearchFilter only objects that contain specific component/s?如何在 SetSearchFilter 中仅过滤包含特定组件的对象?
【发布时间】:2018-10-29 17:24:01
【问题描述】:

在 CustomEditor 脚本中,我用黄色对象着色,这些对象附加了特定组件(在本例中为 Mesh Renderer)。

using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
//Adapted from Unity3DCollege YouTube Video Tutorial https://www.youtube.com/watch?v=pdDrY8Mc2lU
[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;
    public static List<string> componentsList = new List<string>();

    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 (gameObj.GetComponent<MeshRenderer>() == true)
                            fontColor = meshRendererColor;
                        else
                            fontColor = prefabModFontColor;

                        break;
                    }
                }
                if (fontColor != prefabModFontColor)
                {
                    if (gameObj.GetComponent<MeshRenderer>() == true)
                        fontColor = meshRendererColor;
                    else
                        fontColor = prefabOrgFontColor;
                }
            }
            else
            {
                if (gameObj.GetComponent<MeshRenderer>() == true)
                    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
            }
            );
        }
    }
}

在 EditorWindow 脚本中,我使用了 SetSearchFilter:

using System;
using UnityEditor;
using UnityEngine;
using System.Collections;
using System.Reflection;

public class HierarchyEditor : EditorWindow
{
    private static SearchableEditorWindow hierarchy { get; set; }
    private string filterText = "";

    [MenuItem("Tools/Hierarchy Editor")]
    public static void ShowWindow()
    {
        GetWindow<HierarchyEditor>("HierarchyEditor");
    }
    private void OnGUI()
    {
        CustomHierarchy.gameObjectFontColor = EditorGUILayout.ColorField("Original Font Color", CustomHierarchy.gameObjectFontColor);
        CustomHierarchy.prefabOrgFontColor = EditorGUILayout.ColorField("Prefab Original Font Color", CustomHierarchy.prefabOrgFontColor);
        CustomHierarchy.prefabModFontColor = EditorGUILayout.ColorField("Prefab Modified Font Color", CustomHierarchy.prefabModFontColor);
        CustomHierarchy.inActiveColor = EditorGUILayout.ColorField("Inactive Color", CustomHierarchy.inActiveColor);
        CustomHierarchy.meshRendererColor = EditorGUILayout.ColorField("Mesh Renderer Color", CustomHierarchy.meshRendererColor);

        filterText = GUI.TextField(new Rect(30,190,120,30),filterText, 25);

        SetSearchFilter(filterText, 1);
    }

    public const int FILTERMODE_ALL = 0;
    public const int FILTERMODE_NAME = 1;
    public const int FILTERMODE_TYPE = 2;

    public static void SetSearchFilter(string filter, int filterMode)
    {
        SearchableEditorWindow[] windows = (SearchableEditorWindow[])Resources.FindObjectsOfTypeAll(typeof(SearchableEditorWindow));

        foreach (SearchableEditorWindow window in windows)
        {
            if (window.GetType().ToString() == "UnityEditor.SceneHierarchyWindow")
            {
                hierarchy = window;
                break;
            }
        }

        if (hierarchy == null)
            return;

        MethodInfo setSearchType = typeof(SearchableEditorWindow).GetMethod("SetSearchFilter", BindingFlags.NonPublic | BindingFlags.Instance);
        object[] parameters = new object[] { filter, filterMode, false };

        setSearchType.Invoke(hierarchy, parameters); 
    }
}

我在这里输入 filterText TextField,在这种情况下它是按名称过滤的。

但我想按名称过滤,但也只过滤附加到网格渲染器组件的对象。不是 FILTERMODE_TYPE,而是附加了 Mesh Renderer 组件的对象。所以过滤模式应该是Name(1) 还要同时用mesh renderer过滤对象。

我尝试在 OnGUI 中添加两行: 这两行是:

System.Type type = SceneModeUtility.SearchBar(typeof(BoxCollider), typeof(MeshRenderer));
SceneModeUtility.SearchForType(type);

然后在 EditorWindow 中我看到 3 个图标 All BoxCollider MeshRenderer。 如果我单击 BoxCollider,它会使用 boxcollider 过滤所有对象,但是当我在层次结构搜索栏中输入名称时,它将使用名称和框碰撞器过滤所有对象,但是当我再次单击编辑器窗口时,它会将其更改为所有图标。网格渲染器也是如此。

而且我不能同时选择 boxcollider 和 meshrenderer 我只能选择其中一个。

编辑器窗口的屏幕截图:

private void OnGUI()
    {
        CustomHierarchy.gameObjectFontColor = EditorGUILayout.ColorField("Original Font Color", CustomHierarchy.gameObjectFontColor);
        CustomHierarchy.prefabOrgFontColor = EditorGUILayout.ColorField("Prefab Original Font Color", CustomHierarchy.prefabOrgFontColor);
        CustomHierarchy.prefabModFontColor = EditorGUILayout.ColorField("Prefab Modified Font Color", CustomHierarchy.prefabModFontColor);
        CustomHierarchy.inActiveColor = EditorGUILayout.ColorField("Inactive Color", CustomHierarchy.inActiveColor);
        CustomHierarchy.meshRendererColor = EditorGUILayout.ColorField("Mesh Renderer Color", CustomHierarchy.meshRendererColor);

        multipleComponents = GUI.Toggle(new Rect(30, 160, 120, 30), multipleComponents, "Multiple components");
        if(multipleComponents == true)
        {
            GUI.enabled = true;
        }
        else
        {
            GUI.enabled = false;
        }
        multipleComponentsString = GUI.TextField(new Rect(30, 180, 120, 30), multipleComponentsString, 25);

        GUI.enabled = true;
        filterText = GUI.TextField(new Rect(30, 230, 120, 30), filterText, 25);

        System.Type type = SceneModeUtility.SearchBar(typeof(BoxCollider), typeof(MeshRenderer));
        SceneModeUtility.SearchForType(type);
    }

【问题讨论】:

  • 它的工作方式可能与项目的搜索窗口和层次过滤器的工作方式相同。将 "t:" 与组件名称、空格和名称过滤器字符串一起使用。所以 "t:MeshCollider Ham" 将匹配任何带有 MeshCollider 组件且名称中某处有“Ham”的对象。
  • @Foggzie 非常感谢。所以我一无所获,但至少我学到了一些东西。
  • @Foggzie 例如,搜索者找不到的是带有网格渲染器和盒子碰撞器的对象。例如,我有 40 个带有网格渲染器的对象,有些有盒子碰撞器。有没有办法只用网格渲染器和盒子碰撞器过滤对象? (多成分过滤)
  • 我不确定你是否可以做多个,但你可以使用基类,所以你可以用Collider代替MeshColliderBoxCollider

标签: c# unity3d


【解决方案1】:

我注意到您正在使用反射来执行此操作。你不必。有一个未记录的 API,称为 SceneModeUtility,可用于在编辑器中搜索对象。请参阅此here 的非官方 API。使用 Chrome 浏览器即可轻松翻译成英文。

如果您只想在编辑器的 SearchField 中搜索和过滤带有组件 (MeshRenderer) 的对象:

SceneModeUtility.SearchForType(typeof(MeshRenderer));

在 GameObject 上使用多个组件过滤搜索并返回结果:

System.Type type = SceneModeUtility.SearchBar(typeof(MeshRenderer), typeof(Rigidbody));

您可以将任意数量的组件传递给SearchBar 函数。

【讨论】:

  • 我试图将它添加到 OnGUI 内的行中: System.Type type = SceneModeUtility.SearchBar(typeof(BoxCollider), typeof(MeshRenderer)); SceneModeUtility.SearchForType(type);但是然后在编辑器窗口中,我有 3 个图标 All BoxCollider MeshRenderer 如果我单击框碰撞器,它将过滤所有带有框碰撞器的对象,并且对于网格渲染器也是如此,但是当我在层次结构的 searhc 栏中键入名称时,它会将其更改为全部。我可以选择或框碰撞器或网格渲染器,但不能同时选择两种类型。
  • 我用我尝试过的内容和屏幕截图更新了我的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-08
  • 1970-01-01
  • 1970-01-01
  • 2019-06-16
  • 2019-02-07
  • 1970-01-01
  • 2019-07-30
相关资源
最近更新 更多