Unity-EditorGUILayout在Serializable字段内显示隐藏的元素

时间:2019-06-26 19:44:15

标签: c# unity3d unity-editor

我正在使用Unity 2018.3.14f1,并且尝试创建新的ScriptableObject。 这是我的代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Items;
using System;
#if UNITY_EDITOR
using UnityEditor;
#endif

[CreateAssetMenu(fileName = "New Weapon", menuName = "Ingame Item/Weapon")]
public class Weapon : ScriptableObject
{
    public GameObject modelMesh;
    public WeaponType weaponType;
    public SlotType slotType;
    public WeaponTextureMaps[] weaponTextureMaps;


}

[Serializable]
public struct WeaponTextureMaps
{
    public Material material;
    public Texture normalMap;
    public Texture albedoMap;
    public Texture metalicMap;
    public Texture ambientOcullsionMap;
    public bool hasEmission;
    [HideInInspector]
    public Texture emissionMap;
}

#if UNITY_EDITOR
[CustomEditor(typeof(Weapon))]
public class Weapon_Editor : Editor
{
    Weapon script;
    GameObject model;
    SerializedProperty m_weaponTextureMaps;

    public void OnEnable()
    {
        script = (Weapon)target;
        model = script.modelMesh;
    }

    public override void OnInspectorGUI()
    {

        DrawDefaultInspector(); // for other non-HideInInspector fields
        if (GUI.changed)
        {
            if (model.name != script.modelMesh.name)
            {
                model = script.modelMesh;
                int totalMaterials = model.GetComponent<MeshRenderer>().sharedMaterials.Length;
                Array.Resize(ref script.weaponTextureMaps, totalMaterials);
                int i = -1;
                foreach (Material mat in model.GetComponent<MeshRenderer>().sharedMaterials)
                {
                    i++;
                    script.weaponTextureMaps[i].material = mat;
                }

            }
        }
        int ii = -1;
        foreach(WeaponTextureMaps wtm in script.weaponTextureMaps)
        {
            ii++;
            if (wtm.hasEmission == true)
            {
                script.weaponTextureMaps[ii].emissionMap = EditorGUILayout.ObjectField("Emission Map", script.weaponTextureMaps[ii].emissionMap, typeof(Texture), true) as Texture;
            }
        }
    }
}
#endif

enter image description here

当我单击“具有排放”时,隐藏的字段应该出现在“具有排放”按钮下方的“元素0”内。

但是,它出现在“元素0”的外部,而不是内部。我该如何解决?

如何使隐藏字段显示在其元素内部?

1 个答案:

答案 0 :(得分:0)

您的问题是使用DrawDefaultInspector();

这会导致该字段不仅显示在Element 0之外,而且还显示在检查器中的毕竟条目中。


相反,我会为CustomPropertyDrawer做一个合适的WeaponTextureMaps。巨大的优势:您不必每次在脚本中使用WeaponTextureMaps字段时都再次实现自定义编辑器。

    [Serializable]
    public struct WeaponTextureMaps
    {
        public Material material;
        public Texture normalMap;
        public Texture albedoMap;
        public Texture metalicMap;
        public Texture ambientOcullsionMap;
        public bool hasEmission;

        public Texture emissionMap;
    }

#if UNITY_EDITOR
    [CustomPropertyDrawer(typeof(WeaponTextureMaps))]
    public class WeaponTextureMapsDrawer : PropertyDrawer
    {
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            var material = property.FindPropertyRelative("material");
            var normalMap = property.FindPropertyRelative("normalMap");
            var albedoMap = property.FindPropertyRelative("albedoMap");
            var metalicMap = property.FindPropertyRelative("metalicMap");
            var ambientOcullsionMap = property.FindPropertyRelative("ambientOcullsionMap");
            var hasEmission = property.FindPropertyRelative("hasEmission");

            var emissionMap = property.FindPropertyRelative("emissionMap");

            // Using BeginProperty / EndProperty on the parent property means that
            // prefab override logic works on the entire property.
            EditorGUI.BeginProperty(position, label, property);

            // Draw label
            position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);

            EditorGUI.PropertyField(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight), material);
            position.y += EditorGUIUtility.singleLineHeight;

            EditorGUI.PropertyField(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight), normalMap);
            position.y += EditorGUIUtility.singleLineHeight;

            EditorGUI.PropertyField(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight), albedoMap);
            position.y += EditorGUIUtility.singleLineHeight;

            EditorGUI.PropertyField(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight), metalicMap);
            position.y += EditorGUIUtility.singleLineHeight;

            EditorGUI.PropertyField(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight), ambientOcullsionMap);
            position.y += EditorGUIUtility.singleLineHeight;

            EditorGUI.PropertyField(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight), hasEmission);
            position.y += EditorGUIUtility.singleLineHeight;

            if (hasEmission.boolValue)
            {
                EditorGUI.PropertyField(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight), emissionMap);
            }

            EditorGUI.EndProperty();
        }

        public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
        {
            var hasEmission = property.FindPropertyRelative("hasEmission");

            return EditorGUIUtility.singleLineHeight * (hasEmission.boolValue ? 8 : 7);
        }
    }
#endif

结果

enter image description here


对于您的Weapon_Editor,我建议不要将SerializedProperty与直接获取和更改target的值混合使用。代替

[CustomEditor(typeof(Weapon))]
public class Weapon_Editor : Editor
{
    SerializedProperty model;
    SerializedProperty weaponType;
    SerializedProperty slotType;
    SerializedProperty weaponTextureMaps;

    // Link all script fields
    public void OnEnable()
    {
        model = serializedObject.FindProperty("modelMesh");
        weaponType = serializedObject.FindProperty("weaponType");
        slotType = serializedObject.FindProperty("slotType");
        weaponTextureMaps = serializedObject.FindProperty("weaponTextureMaps");
    }

    public override void OnInspectorGUI()
    {
        // Draw the Script field
        EditorGUI.BeginDisabledGroup(true);
        {
            EditorGUILayout.ObjectField("Script", MonoScript.FromScriptableObject((Weapon)target), typeof(Weapon), false);
        }
        EditorGUI.EndDisabledGroup();

        // load current values into the serialized fields
        serilaizedObject.Update();

        EditorGUI.BeginChangeCheck();
        {
            EditorGUILayout.PropertyField(model);
        }
        // runs everytime the model is changed
        if (EditorGUI.EndChangeCheck())
        {
            if(model.objectReferenceValue == null)
            {
                weaponTextureMaps.arraySize = 0;
            }
            else
            {
                // get the renderer fromt he SerializedProperty
                var renderer = ((GameObject)model.objectReferenceValue).GetComponent<Renderer>();

                if(renderer == null)
                {
                     weaponTextureMaps.arraySize = 0;
                }
                else
                {
                    int totalMaterials = renderer.sharedMaterials.Length;

                    weaponTextureMaps.arraySize = totalMaterials;

                    // set the material references
                    for (var i = 0; i < totalMaterials; i++)
                    {
                        weaponTextureMaps.GetArrayElementAtIndex(i).FindPropertyRelative("material").objectReferenceValue = renderer.sharedMaterials[i];
                    }
                }
            }
        }

        EditorGUILayout.PropertyField(weaponType);EditorGUILayout.PropertyField(slotType);

        // Note you have to pass true in order to see sub-fields
        EditorGUILayout.PropertyField(weaponTextureMaps, true);

        // Note that without that any changes to SerializedProperties does absolutely nothing
        serializedObject.ApplyModifiedProperties();
    }
}
#endif