给你的Unity编辑器添加实现类似 Odin 的 条件显示字段 (ShowIf/HideIf) 功能

自己常用的一个预制功能模块,用到这个开关显示的功能,但又不想依赖Odin。

一个是自己穷,用不起Odin,二是如果我的包给别人用,依赖的太多而且还是收费的,会不会被人炸掉祖坟。

一、效果演示

在脚本的观察面板上,通过一些变量开关,显示和隐藏某些字段。

目前Unity没有这个Attribute,所以要么你用诸如Odin,要么自己用AI搓一个

二、需求来源

自己常用的一个预制功能模块,用到这个开关显示的功能,但又不想依赖Odin。

一个是自己穷,用不起Odin,二是如果我的包给别人用,依赖的太多而且还是收费的,会不会被人炸掉祖坟。

三、功能脚本组成

脚本1,Editor下:ConditionalFieldDrawer.cs,注意,必须放在Editor下

脚本2,Runtime下:ConditionalFieldAttribute.cs,不能放在Editor下

脚本3,测试脚本:Demo.cs

挂载后到物体并测试:

四、源码

1、ConditionalFieldDrawer.cs 清单

csharp 复制代码
using UnityEditor;
using UnityEngine;

[CustomPropertyDrawer(typeof(ConditionalFieldAttribute))]
public class ConditionalFieldDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        ConditionalFieldAttribute condHAtt = (ConditionalFieldAttribute)attribute;

        // 找到比较的字段
        SerializedProperty comparedField = property.serializedObject.FindProperty(condHAtt.ComparedPropertyName);
        if (comparedField != null && comparedField.propertyType == SerializedPropertyType.Boolean)
        {
            bool enabled = comparedField.boolValue == condHAtt.ExpectedValue;
            if (enabled)
            {
                EditorGUI.PropertyField(position, property, label, true);
            }
        }
        else
        {
            // 如果字段没找到,正常显示
            EditorGUI.PropertyField(position, property, label, true);
        }
    }

    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        ConditionalFieldAttribute condHAtt = (ConditionalFieldAttribute)attribute;

        SerializedProperty comparedField = property.serializedObject.FindProperty(condHAtt.ComparedPropertyName);
        if (comparedField != null && comparedField.propertyType == SerializedPropertyType.Boolean)
        {
            bool enabled = comparedField.boolValue == condHAtt.ExpectedValue;
            return enabled ? EditorGUI.GetPropertyHeight(property, label, true) : 0;
        }

        return EditorGUI.GetPropertyHeight(property, label, true);
    }
}

2、ConditionalFieldAttribute.cs 清单

csharp 复制代码
using System;
using UnityEngine;

[AttributeUsage(AttributeTargets.Field, AllowMultiple = true, Inherited = true)]
public class ConditionalFieldAttribute : PropertyAttribute
{
    public string ComparedPropertyName { get; private set; }
    public bool ExpectedValue { get; private set; }

    public ConditionalFieldAttribute(string comparedPropertyName, bool expectedValue = true)
    {
        this.ComparedPropertyName = comparedPropertyName;
        this.ExpectedValue = expectedValue;
    }
}

3、Demo.cs 清单

csharp 复制代码
using UnityEngine;

public class ConditionalFieldTest : MonoBehaviour
{
    [Header("总开关")]
    public bool masterSwitch;

    [Header("子选项,只在 masterSwitch == true 时显示")]
    [ConditionalField(nameof(masterSwitch), true)]
    public bool optionA;

    [ConditionalField(nameof(masterSwitch), true)]
    public bool optionB;

    [Header("反向测试:只有当 masterSwitch == false 时才显示")]
    [ConditionalField(nameof(masterSwitch), false)]
    public string hiddenMessage = "当 masterSwitch == false 时才看得见";

    [Header("多层嵌套测试")]
    public bool subSwitch;

    [ConditionalField(nameof(subSwitch), true)]
    public int subValue;
}

五、致谢:

感谢GPT,从前的搜索时代是信息平权,现在的GPT时代是知识平权。

网友说:三天不学习,赶不上GPT。