如何只添加一次[InitializeOnLoad]脚本中的列表?

时间:2018-11-08 05:48:28

标签: c# unity3d

使用InitializeOnLoad时,该问题一直无效。 然后,即使我在脚本顶部为列表创建一次实例,它也会一直为它创建实例,并将越来越多的项目添加到列表中。

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

[InitializeOnLoad]
public static class CustomHierarchy
{
    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<GameObject> gameobjectsHasAll = new List<GameObject>();

    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)))
                        {
                            if (!gameobjectsHasAll.Contains(gameObj))
                                gameobjectsHasAll.Add(gameObj);
                            fontColor = meshRendererColor;
                        }
                        else
                        {
                            fontColor = prefabModFontColor;
                        }

                        break;
                    }
                }
                if (fontColor != prefabModFontColor)
                {
                    if (HasAllComponents(gameObj, typeof(MeshRenderer), typeof(BoxCollider)))
                    {
                        gameobjectsHasAll.Add(gameObj);
                        fontColor = meshRendererColor;
                    }
                    else
                    {
                        fontColor = prefabOrgFontColor;
                    }
                }
            }
            else
            {
                if (HasAllComponents(gameObj, typeof(MeshRenderer), typeof(BoxCollider)))
                {
                    gameobjectsHasAll.Add(gameObj);
                    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;
    }
}

List变量是:

public static List<GameObject> gameobjectsHasAll = new List<GameObject>();

例如,在每个具有HasAllComponents的位置的代码中的3个地方,我将对象添加到列表中:

if (HasAllComponents(gameObj, typeof(MeshRenderer), typeof(BoxCollider)))
                    {
                        gameobjectsHasAll.Add(gameObj);
                        fontColor = meshRendererColor;
                    }

在层次结构中,我有6个满足HasAllComponents条件的项目。 但是列表第一次包含36个项目时,它会连续6次添加6个项目。

然后接下来的120个左右项目将不停地添加相同的项目。 我从另一个脚本EditorWindow脚本调用此列表:

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

public class HierarchyEditor : EditorWindow
{
    public static bool multipleComponents = false;
    public static string multipleComponentsString = "";

    private static SearchableEditorWindow hierarchy { get; set; }
    private string filterText = "";
    private string oldFilterText = "";

    [MenuItem("Tools/Hierarchy Editor")]
    public static void ShowWindow()
    {
        GetWindow<HierarchyEditor>("HierarchyEditor");

        Test();
    }

测试在哪里

private static void Test()
    {
        var all = CustomHierarchy.gameobjectsHasAll;
    }

2 个答案:

答案 0 :(得分:1)

在所有行之前

gameobjectsHasAll.Add(gameObj);

检查对象是否已在列表中,仅在尚不存在时添加它

if(!gameobjectsHasAll.Contains(gameObj))
{
    gameobjectsHasAll.Add(gameObj);
    fontColor = meshRendererColor;
}

到目前为止,您似乎只检查了一次。

答案 1 :(得分:1)

我相信,在将其分配给EditorApplication.hierarchyWindowItemOnGUI委托时,您只需处理HandleHierarchyWindowItemOnGUI方法中的一个元素。手册说:“为HierarchyWindow中的每个可见列表项目委托OnGUI事件。” (https://docs.unity3d.com/ScriptReference/EditorApplication-hierarchyWindowItemOnGUI.html),因此对于每个列表元素(您有6个),它将再次为每个元素调用它。这是一个统一的生命周期(https://docs.unity3d.com/Manual/ExecutionOrder.html),您会看到它不断调用OnGUI(),因此当您列出的是静态实例时,原因是它不会从中删除先前的对象,因此会作为OnGUI()处理列表并创建通过检查的新实例,列表会越来越大。

因此,您可能想在再次处理它之前清除HandleHierarchyWindowItemOnGUI方法中的列表。