C# 如何使用bool在Unity inspector中启用/禁用列表?

C# 如何使用bool在Unity inspector中启用/禁用列表?,c#,unity3d,unity-editor,C#,Unity3d,Unity Editor,我有一个名为Level的ScriptableObject脚本,在Level脚本中我有一个游戏对象列表和一个名为introductenewenemies的bool变量 我想做的是:我想在bool变量打开时启用游戏对象列表,在关闭时使用Unity自定义检查器方法或属性抽屉隐藏/灰显(我们无法向其添加元素)。有那么难吗?要隐藏变量,请查看 但如果您想灰显一个字段,您可以这样做。最好的方法是自定义属性。我将从显示最终结果开始: 使用字段隐藏/显示其他字段: public bool showHideLi

我有一个名为
Level
ScriptableObject
脚本,在Level脚本中我有一个游戏对象列表和一个名为
introductenewenemies
的bool变量


我想做的是:我想在bool变量打开时启用游戏对象列表,在关闭时使用Unity自定义检查器方法或属性抽屉隐藏/灰显(我们无法向其添加元素)。有那么难吗?

要隐藏变量,请查看


但如果您想灰显一个字段,您可以这样做。

最好的方法是自定义属性。我将从显示最终结果开始:

  • 使用字段隐藏/显示其他字段:

    public bool showHideList = false; 
    [ShowIf(ActionOnConditionFail.DontDraw, ConditionOperator.And, nameof(showHideList))]
    public string aField = "item 1";
    
    public bool enableDisableList = false;
    
    [ShowIf(ActionOnConditionFail.JustDisable, ConditionOperator.And, 
    nameof(enableDisableList))]
    public string anotherField = "item 2";
    

  • 使用一个字段启用/禁用另一个字段:

    public bool showHideList = false; 
    [ShowIf(ActionOnConditionFail.DontDraw, ConditionOperator.And, nameof(showHideList))]
    public string aField = "item 1";
    
    public bool enableDisableList = false;
    
    [ShowIf(ActionOnConditionFail.JustDisable, ConditionOperator.And, 
    nameof(enableDisableList))]
    public string anotherField = "item 2";
    

  • 使用方法获取条件值:

    [ShowIf(ActionOnConditionFail.JustDisable, ConditionOperator.And,nameof(CalculateIsEnabled))]
    public string yetAnotherField = "one more";    public 
    bool CalculateIsEnabled()    
    {
        return true;    
    }
    

  • 在同一字段上使用多个条件:

    public bool condition1;    
    public bool condition2;    
    [ShowIf(ActionOnConditionFail.JustDisable, ConditionOperator.And, nameof(condition1), 
    nameof(condition2))]    
    public string oneLastField= "last field";
    


是怎么做到的?
  • 定义同时允许多个条件的选项:

    public enum ConditionOperator
    {
        // A field is visible/enabled only if all conditions are true.
        And,
        // A field is visible/enabled if at least ONE condition is true.
        Or,
    }
    
  • 定义在条件失败时如何绘制字段:

    public enum ActionOnConditionFail
    {
        // If condition(s) are false, don't draw the field at all.
        DontDraw,
        // If condition(s) are false, just set the field as disabled.
        JustDisable,
    }
    
  • 现在创建一个自定义属性类,以保存有关条件的数据:

    using System;
    using UnityEngine;
    [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
    public class ShowIfAttribute : PropertyAttribute
    {
        public ActionOnConditionFail Action {get;private set;}
        public ConditionOperator Operator {get;private set;}
        public string[] Conditions {get;private set;}
    
         public ShowIfAttribute(ActionOnConditionFail action, ConditionOperator conditionOperator, params string[] conditions)
        {
            Action  = action;
            Operator = conditionOperator;
            Conditions = conditions;
        }
    }
    
  • 在告诉unity如何使用
    ShowIfAttribute
    处理字段的重要部分,此抽屉脚本需要位于任何“编辑器”文件夹下:

    using System.Reflection;
    using UnityEditor;
    using System.Collections.Generic;
    using System;
    using System.Linq;
    using UnityEngine;
    
    [CustomPropertyDrawer(typeof(ShowIfAttribute), true)]
    public class ShowIfAttributeDrawer : PropertyDrawer
    {
    
        #region Reflection helpers.
        private static MethodInfo GetMethod(object target, string methodName)
        {
            return GetAllMethods(target, m => m.Name.Equals(methodName, 
                      StringComparison.InvariantCulture)).FirstOrDefault();
        }
    
        private static FieldInfo GetField(object target, string fieldName)
        {
            return GetAllFields(target, f => f.Name.Equals(fieldName, 
                  StringComparison.InvariantCulture)).FirstOrDefault();
        }
        private static IEnumerable<FieldInfo> GetAllFields(object target, Func<FieldInfo, 
                bool> predicate)
        {
            List<Type> types = new List<Type>()
                {
                    target.GetType()
                };
    
            while (types.Last().BaseType != null)
            {
                types.Add(types.Last().BaseType);
            }
    
            for (int i = types.Count - 1; i >= 0; i--)
            {
                IEnumerable<FieldInfo> fieldInfos = types[i]
                    .GetFields(BindingFlags.Instance | BindingFlags.Static | 
       BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly)
                    .Where(predicate);
    
                foreach (var fieldInfo in fieldInfos)
                {
                    yield return fieldInfo;
                }
            }
        }
        private static IEnumerable<MethodInfo> GetAllMethods(object target, 
      Func<MethodInfo, bool> predicate)
        {
            IEnumerable<MethodInfo> methodInfos = target.GetType()
                .GetMethods(BindingFlags.Instance | BindingFlags.Static | 
      BindingFlags.NonPublic | BindingFlags.Public)
                .Where(predicate);
    
            return methodInfos;
        }
        #endregion
    
        private bool MeetsConditions(SerializedProperty property)
        {
            var showIfAttribute = this.attribute as ShowIfAttribute;
            var target = property.serializedObject.targetObject;
            List<bool> conditionValues = new List<bool>();
    
            foreach (var condition in showIfAttribute.Conditions)
            {
                FieldInfo conditionField = GetField(target, condition);
                if (conditionField != null &&
                    conditionField.FieldType == typeof(bool))
                {
                    conditionValues.Add((bool)conditionField.GetValue(target));
                }
    
                MethodInfo conditionMethod = GetMethod(target, condition);
                if (conditionMethod != null &&
                    conditionMethod.ReturnType == typeof(bool) &&
                    conditionMethod.GetParameters().Length == 0)
                {
                    conditionValues.Add((bool)conditionMethod.Invoke(target, null));
                }
            }
    
            if (conditionValues.Count > 0)
            {
                bool met;
                if (showIfAttribute.Operator == ConditionOperator.And)
                {
                    met = true;
                    foreach (var value in conditionValues)
                    {
                        met = met && value;
                    }
                }
                else
                {
                    met = false;
                    foreach (var value in conditionValues)
                    {
                        met = met || value;
                    }
                }
                return met;
            }
            else
            {
                Debug.LogError("Invalid boolean condition fields or methods used!");
                return true;
            }
        }
        public override float GetPropertyHeight(SerializedProperty property, GUIContent 
                     label)
        {
            // Calcluate the property height, if we don't meet the condition and the draw 
        mode is DontDraw, then height will be 0.
            bool meetsCondition = MeetsConditions(property);
            var showIfAttribute = this.attribute as ShowIfAttribute;
    
            if (!meetsCondition && showIfAttribute.Action == 
                                           ActionOnConditionFail.DontDraw)
                return 0;
            return base.GetPropertyHeight(property, label);
        }
    
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent 
               label)
        {
            bool meetsCondition = MeetsConditions(property);
            // Early out, if conditions met, draw and go.
            if (meetsCondition)
            {
                EditorGUI.PropertyField(position, property, label, true);
                return; 
            }
    
            var showIfAttribute = this.attribute as ShowIfAttribute;
            if(showIfAttribute.Action == ActionOnConditionFail.DontDraw)
            {
                return;
            }
            else if (showIfAttribute.Action == ActionOnConditionFail.JustDisable)
            {
                EditorGUI.BeginDisabledGroup(true);
                EditorGUI.PropertyField(position, property, label, true);
                EditorGUI.EndDisabledGroup();
            }
    
        }
    }
    
    使用系统反射;
    使用UnityEditor;
    使用System.Collections.Generic;
    使用制度;
    使用System.Linq;
    使用UnityEngine;
    [CustomPropertyDrawer(typeof(ShowIfAttribute),true)]
    公共类ShowIfAttributedDrawer:PropertyDrawer
    {
    #区域反射助手。
    私有静态MethodInfo GetMethod(对象目标,字符串methodName)
    {
    返回GetAllMethods(target,m=>m.Name.Equals(methodName,
    StringComparison.InvariantCulture().FirstOrDefault();
    }
    私有静态FieldInfo GetField(对象目标,字符串fieldName)
    {
    返回GetAllFields(target,f=>f.Name.Equals(fieldName,
    StringComparison.InvariantCulture().FirstOrDefault();
    }
    私有静态IEnumerable GetAllFields(对象目标,Func谓词)
    {
    列表类型=新列表()
    {
    target.GetType()
    };
    while(types.Last().BaseType!=null)
    {
    添加(types.Last().BaseType);
    }
    对于(int i=types.Count-1;i>=0;i--)
    {
    IEnumerable fieldInfos=类型[i]
    .GetFields(BindingFlags.Instance | BindingFlags.Static |
    BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly)
    .Where(谓语);
    foreach(fieldInfo中的var fieldInfo)
    {
    收益率返回字段信息;
    }
    }
    }
    私有静态IEnumerable GetAllMethods(对象目标,
    Func谓词)
    {
    IEnumerable methodInfos=target.GetType()
    .GetMethods(BindingFlags.Instance | BindingFlags.Static |
    BindingFlags.NonPublic | BindingFlags.Public)
    .Where(谓语);
    返回方法信息;
    }
    #端区
    私有bool MEETSCONDECTIONS(私有财产)
    {
    var showIfAttribute=this.attribute作为showIfAttribute;
    var target=property.serializedObject.targetObject;
    列表条件值=新列表();
    foreach(ShowiAttribute.Conditions中的var条件)
    {
    FieldInfo conditionField=GetField(目标、条件);
    if(conditionField!=null&&
    conditionField.FieldType==typeof(bool))
    {
    添加((bool)conditionField.GetValue(target));
    }
    MethodInfo conditionMethod=GetMethod(目标、条件);
    if(conditionMethod!=null&&
    conditionMethod.ReturnType==typeof(bool)&&
    conditionMethod.GetParameters().Length==0)
    {
    添加((bool)conditionMethod.Invoke(target,null));
    }
    }
    如果(conditionValues.Count>0)
    {
    布尔梅特;
    if(showIfAttribute.Operator==ConditionOperator.And)
    {
    met=真;
    foreach(条件值中的var值)
    {
    满足=满足和价值;
    }
    }
    其他的
    {
    met=假;
    foreach(条件值中的var值)
    {
    met=met | |值;
    }
    }
    回程会议;
    }
    其他的
    {
    LogError(“使用的布尔条件字段或方法无效!”);
    返回true;
    }
    }
    公共覆盖浮点GetPropertyHight(SerializedProperty属性,GUIContent
    标签)
    {
    //如果我们不符合条件和图纸,则计算属性高度
    模式为DontDraw,则高度为0。
    布尔MeetCondition=MeetConditions(属性);
    var showIfAttribute=this.attribute作为showIfAttribute;
    如果(!MeetCondition&&showIfAttribute.Action==
    ActionOnConditionFail.DontDraw)
    返回0;
    返回base.GetPropertyHeight(属性,标签);
    }
    public override void OnGUI(Rect位置、SerializedProperty属性、GUIContent
    标签)
    {
    布尔MeetCondition=MeetConditions(属性);
    //提前退出,如果条件满足,抽签离开。
    如果(满足条件)
    {
    EditorGUI.PropertyField(位置、属性、标签、true);
    返回;
    }
    var showIfAttribute=this.attribute作为showIfAttribute;
    if(showIfAttribute.Action==ActionOnConditionFail.DontDraw)
    {
    返回;
    }
    else if(showIfAttribute.Action==ActionOnConditionFail.JustDisable)