定制检视窗口:使用自定义的属性

ConditionalProperty 根据条件显示对应的变量

根据条件显示对应的变量.gif

所需脚本

创建 ConditionalPropertyAttribute,继承PropertyAttribute
设置该属性所需的参数

  • 要参考的变量的名称(是枚举类型,最终要获取该变量当前值用于比较)
  • 自身的值(上述枚举中的某个值)

创建ConditionalPropertyAttributeDrawer,继承PropertyDrawer
定义属性ConditionalProperty的规则:比较属性中参考变量的值和自身的值

  • 相等:则显示该属性修饰的变量
  • 不相等:不显示该属性修饰的变量

具体代码
ConditionalPropertyAttribute.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 可以放在工程的任何地方
/// 创建一个属性来修饰代码:要检查的的属性值、要与前述值对比的值
/// </summary>
public class ConditionalPropertyAttribute : PropertyAttribute
{
    public string propertyToCheck;
    public object compareValue;

    public ConditionalPropertyAttribute(string propertyToCheck, object compareValue)
    {
        this.propertyToCheck = propertyToCheck;
        this.compareValue = compareValue;
    }
}

ConditionalPropertyAttributeDrawer.cs

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

/// <summary>
/// 应位于“Editor”目录下,因为引用了UnityEditor。否则打包时会报错(在Unity编辑器中不会报错)
/// </summary>

// 自定义该属性的绘制形式
[CustomPropertyDrawer(typeof(ConditionalPropertyAttribute))]
public class ConditionalPropertyAttributeDrawer : PropertyDrawer
{
    // 在position处将property以lable(图、文、说明文字Tooltip)的形式显示出来
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        bool isVisible = IsVisible(property);

        if (isVisible)
        {
            EditorGUI.BeginProperty(position, label, property);
            EditorGUI.PropertyField(position, property, label, true);
            EditorGUI.EndProperty();
        }
    }

    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        bool isVisible = IsVisible(property);

        float height = 0;
        if (isVisible)
            height = EditorGUI.GetPropertyHeight(property);

        return height;
    }

    private bool IsVisible(SerializedProperty property)
    {
        var conditionalPropertyAttribute = this.attribute as ConditionalPropertyAttribute;
        if (conditionalPropertyAttribute == null)
            Debug.LogError("ConditionPropertyAttributeDrawer couldn't cast attribute to ConditionalPropertyAttribute");

        string propertyToCheckName = conditionalPropertyAttribute.propertyToCheck;

        // 该值与下述实际值一致时,才在Inspector中显示其修饰的变量内容
        string requiredValue = "null";
        if (conditionalPropertyAttribute.compareValue != null)
            requiredValue = conditionalPropertyAttribute.compareValue.ToString();

        bool isVisible = true;

        if (!string.IsNullOrEmpty(propertyToCheckName))
        {
            // 找到名为propertyToCheckName的变量,获取其(是一个枚举)当前的值
            var propertyToCheck = property.serializedObject.FindProperty(propertyToCheckName);
            if (propertyToCheck != null)
            {
                // 当前实际的值
                string actualValue = propertyToCheck.enumNames[propertyToCheck.enumValueIndex];
                //  StringComparison.OrdinalIgnoreCase:使用序号排序规则并忽略被比较字符串的大小写,对字符串进行比较。
                isVisible = string.Equals(requiredValue, actualValue, System.StringComparison.OrdinalIgnoreCase);
            }
        }
        return isVisible;
    }
}

使用方法

public enum WinCondition
{
    Points,
    SurviveTime,
    EnemyTypeCount
}

public class Win : MonoBehaviour
{
    [Header("胜利的条件")]
    public WinCondition winCondition;

    [ConditionalProperty("winCondition", "Points")]
    public int numPointsToWin = 1500;
    
    [Tooltip("单位:秒")]
    [ConditionalProperty("winCondition", "SurviveTime")]
    public float timeToSurvive = 30;

    [ConditionalProperty("winCondition", "EnemyTypeCount")]
    public bool eatAnyGhostToWin = true;
    [ConditionalProperty("winCondition", "EnemyTypeCount")]
    public int numEnemiesToEat = 10;
}

MinMax 显示最小最大值区间

设置最小最大值.gif

说明

变量使用Vector2类型,其中x表示最小值,y表示最大值
属性MinMax中设置上下限
用滑动条(EditorGUI.MinMaxSlider)显示范围
在下方用Vector4显示下限、当前允许最小值、当前允许最大值,上限(只许看,不许直接修改:GUI.enabled = false;)

使用方式

 // 若showDebugValues = false,则只显示滑动条,不显示下方的具体数值
[MinMax(0, 1, showDebugValues = true)]
public Vector2 volume;

代码

MinMaxAttribute.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MinMaxAttribute : PropertyAttribute
{
    public float minLimit = 0;
    public float maxLimit = 1;
    public bool showEditRange;
    public bool showDebugValues;

    public MinMaxAttribute(int min, int max)
    {
        minLimit = min;
        maxLimit = max;
    }
}

MinMaxDrawer.cs

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

[CustomPropertyDrawer(typeof(MinMaxAttribute))]
public class MinMaxDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        MinMaxAttribute minMax = attribute as MinMaxAttribute;

        if (property.propertyType == SerializedPropertyType.Vector2)
        {
            if (minMax.showDebugValues || minMax.showEditRange)
            {
                position = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);
            }

            float minValue = property.vector2Value.x;
            float maxValue = property.vector2Value.y;
            float minLimit = minMax.minLimit;
            float maxLimit = minMax.maxLimit;

            EditorGUI.MinMaxSlider(position, label, ref minValue, ref maxValue, minLimit, maxLimit);

            Vector2 vec = Vector2.zero;
            vec.x = minValue;
            vec.y = maxValue;

            property.vector2Value = vec;

            if (minMax.showDebugValues || minMax.showEditRange)
            {
                bool isEditable = false;
                if (minMax.showEditRange)
                    isEditable = true;

                if (!isEditable)
                    GUI.enabled = false;

                position.y += EditorGUIUtility.singleLineHeight;

                Vector4 val = new Vector4(minLimit, minValue, maxValue, maxLimit);
                val = EditorGUI.Vector4Field(position, "MinLimit/MinVal/MaxVal/MaxLimit", val);

                GUI.enabled = false;
                position.y += EditorGUIUtility.singleLineHeight;
                // EditorGUI.FloatField(position, "Selected Range", maxValue - minValue);
                GUI.enabled = true;

                if (isEditable)
                    property.vector2Value = new Vector2(val.y, val.z);
            }
        }
    }

    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        MinMaxAttribute minMax = attribute as MinMaxAttribute;

        float size = EditorGUIUtility.singleLineHeight;

        if (minMax.showEditRange || minMax.showDebugValues)
        {
            size += EditorGUIUtility.singleLineHeight;
        }

        return size;
    }
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容