我有一个名为ScriptableObject
的{{1}}脚本,在关卡脚本中有一个GameObjects列表和一个名为Level
的布尔变量。
我想做的是:我想在启用bool变量时启用该游戏对象列表,并在关闭时使用Unity自定义检查器启用它的“隐藏/灰色”显示(我们不能向其中添加元素)方法或属性抽屉。很难吗?
答案 0 :(得分:1)
最好的方法是自定义属性。我将从显示最终结果开始:
使用一个字段隐藏/显示另一个字段:
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;
}
}
我们要告诉人们如何使用ShowIfAttribute
处理字段的最棘手的部分,此Drawer脚本必须位于任何“ Editor”文件夹下:
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();
}
}
}
答案 1 :(得分:0)
public class Test : MonoBehaviour
{
[SerializeField]
bool openFlag = false;
bool prevOpenFlag = false;
void Update()
{
if(prevOpenFlag != openFlag)
{
if (openFlag == true)
{
Open();
prevOpenFlag = openFlag;
}else
{
Close();
prevOpenFlag = openFlag;
}
}
}
答案 2 :(得分:-1)