【问题标题】:Unity - EditorGUILayout show hidden element inside Serializable fieldUnity - EditorGUILayout 在可序列化字段中显示隐藏元素
【发布时间】:2019-06-27 04:52:57
【问题描述】:

我正在使用 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

当我单击“已发射”时,隐藏字段应出现在“已发射”按钮下方的“元素 0”内。

但是,它出现在“元素 0”之外,而不是在里面。我该如何解决?

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

【问题讨论】:

    标签: c# unity3d unity-editor


    【解决方案1】:

    您的问题是使用DrawDefaultInspector();

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


    相反,我会为WeaponTextureMaps 创建一个适当的CustomPropertyDrawer。巨大的优势:每次在脚本中使用 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
    

    结果


    对于您的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
    

    【讨论】:

      猜你喜欢
      • 2012-03-11
      • 1970-01-01
      • 2020-03-10
      • 1970-01-01
      • 2015-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多