参考
Unity实现多选枚举
unity 多选枚举
【Unity】在Inspector上显示自定义的位掩码枚举(Flags)
Unity 实现枚举多选
这个功能在实际开发中,其实很少用到。但大家在平常的使用中,其实经常遇到。摄像机Camera的Clear Flags 和Culling Mask属性都是典型的例子。它的作用在这里体现出来,当你的属性有很多值,并且这些值还可以多选时,使用枚举多选就非常方便了。

一、示例
1.Scripts/EnumFlags.cs 做个自定义标签
using UnityEngine;
public class EnumFlags : PropertyAttribute
{
}
2.Scripts/EnumTenToTwo.cs 实际测试用的脚本,使用了EnumFlags标签
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum BookCount
{
One = 1,
Two = 2,
Three = 4,
Four = 8,
Five = 16,
Six = 32,
Seven = 64,
Eight = 128,
Nine = 256,
Ten = 512,
Eleven = 1024
}
public class EnumTenToTwo : MonoBehaviour
{
[EnumFlags]
public BookCount bookCount;
public static EnumTenToTwo instance;
void Awake()
{
instance = this;
}
// Start is called before the first frame update
void Start()
{
SwitchState(bookCount);
}
// Update is called once per frame
void Update()
{
}
public void Number()
{
}
private void SwitchState(BookCount type)
{
if ((BookCount.One & type) == BookCount.One) //&判断type是否存在one这个枚举,与one做判断,
{
Debug.Log("我进入One环节");
}
if ((BookCount.Two & type) == BookCount.Two)
{
Debug.Log("我进入Two环节");
}
if ((BookCount.Three & type) == BookCount.Three)
{
Debug.Log("我进入There环节");
}
if ((BookCount.Four & type) == BookCount.Four)
{
Debug.Log("我进入Four环节");
}
if ((BookCount.Five & type) == BookCount.Five)
{
Debug.Log("我进入Five环节");
}
if ((BookCount.Six & type) == BookCount.Six)
{
Debug.Log("我进入Six环节");
}
if ((BookCount.Seven & type) == BookCount.Seven)
{
Debug.Log("我进入Seven环节");
}
if ((BookCount.Eight & type) == BookCount.Eight)
{
Debug.Log("我进入Eight环节");
}
if ((BookCount.Nine & type) == BookCount.Nine)
{
Debug.Log("我进入Nine环节");
}
if ((BookCount.Ten & type) == BookCount.Ten)
{
Debug.Log("我进入Ten环节");
}
if ((BookCount.Eleven & type) == BookCount.Eleven)
{
Debug.Log("我进入Eleven环节");
}
}
}
3.Editor/EnumFlagsAttributeDrawer.cs
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(EnumFlags))]
public class EnumFlagsAttributeDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
property.intValue = EditorGUI.MaskField(position, label, property.intValue
, property.enumNames);
}
}

二、MaskField
https://docs.unity.cn/cn/current/ScriptReference/EditorGUI.MaskField.html
public static int MaskField (Rect position, GUIContent label, int mask, string[] displayedOptions, GUIStyle style= EditorStyles.popup);
public static int MaskField (Rect position, string label, int mask, string[] displayedOptions, GUIStyle style= EditorStyles.popup);
public static int MaskField (Rect position, int mask, string[] displayedOptions, GUIStyle style= EditorStyles.popup);
参数
- position 屏幕上用于此控件的矩形。
- label 字段的标签。
- mask 要显示的当前掩码。
- displayedOption 包含每个标志的标签的字符串数组。
- style 可选 GUIStyle。
- displayedOptions 包含每个标志的标签的字符串数组。
创建一个适用于掩码的字段。注意:与菜单中的每个选项相关联的标志的掩码值将为从 1 开始的连续 2 次幂(即 1、2、4、8、16,以此类推)。

这里可以对照上面示例中的代码,比如从 1 开始的连续 2 次幂
public enum BookCount
{
One = 1,
Two = 2,
Three = 4,
Four = 8,
Five = 16,
Six = 32,
Seven = 64,
Eight = 128,
Nine = 256,
Ten = 512,
Eleven = 1024
}
三、示例
1.Scripts/EnumFlags.cs 做个自定义标签
using UnityEngine;
public class EnumFlags : PropertyAttribute
{
}
2.MyWdsCompoment.cs
using UnityEngine;
using System.Collections;
public enum LayerMaskEnum
{
Layer1,
Layer2,
Layer3,
Layer4,
Layer5,
Layer6,
Layer7,
Layer8,
Layer9,
Layer10
}
public class MyWdsCompoment : MonoBehaviour
{
[EnumFlags]
public LayerMaskEnum layer;
[ContextMenu("输出Layer值")]
public void DebugPrint()
{
Debug.Log("layer=" + (int)layer);
Debug.Log(IsSelectEventType(LayerMaskEnum.Layer10));
}
//判断是否选择了该枚举值
public bool IsSelectEventType(LayerMaskEnum _eventType)
{
// 将枚举值转换为int 类型, 1 左移
int index = 1 << (int)_eventType;
// 获取所有选中的枚举值
int eventTypeResult = (int)layer;
// 按位 与
if ((eventTypeResult & index) == index)
{
return true;
}
return false;
}
}
3.EnumFlagsAttributeDrawer1.cs
using UnityEngine;
using System.Collections;
using UnityEditor;
[CustomPropertyDrawer(typeof(EnumFlags))]
public class EnumFlagsAttributeDrawer1 : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
/*
* 绘制多值枚举选择框,0 全部不选, -1 全部选中, 其他是枚举之和
* 枚举值 = 当前下标值 ^ 2
* 默认[0^2 = 1 , 1 ^2 = 2, 4, 16 , .....]
*/
property.intValue = EditorGUI.MaskField(position, label, property.intValue
, property.enumNames);
}
}

当我们选中layer值后,比如

输出Layer值,发现是10,也就是Layer2对应2,Layer4对应8。不过代码中LayerMaskEnum的值,并没有按照1,2,4,8这种顺序去枚举定义,难道MaskField方法自动纠正了??
网友评论