gpt4 book ai didi

c# - 如何使用 bool 值在 Unity 检查器中启用/禁用列表?

转载 作者:行者123 更新时间:2023-12-04 01:38:45 30 4
gpt4 key购买 nike

我有一个 ScriptableObject脚本调用 Level ,在关卡脚本中,我有一个游戏对象列表和一个名为 introduceNewEnemies 的 bool 变量.

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

最佳答案

最好的方法是自定义属性。我将首先展示最终结果:

  • 使用一个字段来隐藏/显示另一个字段:
    public bool showHideList = false; 
    [ShowIf(ActionOnConditionFail.DontDraw, ConditionOperator.And, nameof(showHideList))]
    public string aField = "item 1";

    Image from Gyazo
  • 使用一个字段来启用/禁用另一个字段:
    public bool enableDisableList = false;

    [ShowIf(ActionOnConditionFail.JustDisable, ConditionOperator.And,
    nameof(enableDisableList))]
    public string anotherField = "item 2";

    Image from Gyazo
  • 使用方法获取条件值:
    [ShowIf(ActionOnConditionFail.JustDisable, ConditionOperator.And,nameof(CalculateIsEnabled))]
    public string yetAnotherField = "one more"; public
    bool CalculateIsEnabled()
    {
    return true;
    }

    Image from Gyazo
  • 在同一字段上使用多个条件:
    public bool condition1;    
    public bool condition2;
    [ShowIf(ActionOnConditionFail.JustDisable, ConditionOperator.And, nameof(condition1),
    nameof(condition2))]
    public string oneLastField= "last field";

    Image from Gyazo


  • 是怎么做的?
  • 定义一次允许多个条件的选项:
    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 处理字段的重要部分,此 Drawer 脚本需要位于任何“编辑器”文件夹下:
    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();
    }

    }
    }

  • 下一步
  • 实现反向条件处理程序,即编辑它以在条件为假时启用字段,反之亦然。
  • 目前对于列表和数组,unit 将禁用/启用列表的元素,但保持启用列表计数字段,尝试实现一种解决方案来处理这种情况。
  • 关于c# - 如何使用 bool 值在 Unity 检查器中启用/禁用列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58441744/

    30 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com