这里记录一下在游戏开发中,系统设计及业务逻辑处理中可以用到的枚举的一些小技巧。
集合判断通常用于子集的判断,判断某个大类是否包含某个类型
假设当前我们有一个物品类型的枚举
public enum EItemType
{
// 1001——1004 资源
Food = 1001,
Wood = 1002,
Iron = 1003,
Oil = 1004,
// 1006——1010 碎片
Cap_Debris = 1006,
Cloth_Debris = 1007,
Pant_Debris = 1008,
Shoe_Debris = 1009,
Weppon_Debris = 1010,
// 1011——1013 技能书
Skill_Book_A = 1011,
Skill_Book_B = 1012,
Skill_Book_C = 1013,
// 以上都是物品类型
SINGLE,
// 以下都是物品集合
RESURCE, // 资源
DEBRIS, // 碎片
SKILL_BOOK, // 技能书
// MAX为标记位
MAX,
}
从这个枚举中的注释可以看出 “资源”={“木”,"粮","铁","油","铜"},“碎片"={“衣服碎片”,"武器碎片","裤子碎片","帽子碎片","鞋碎片"} 还有技能书
对于集合的处理可以使用两种方式,一是数组,二是通过按位与或运算,通过数组的方式就不说了,这里记录一下按位与或运算的方式。
集合判断工具类
public static class ItemTypeUtil
{
private static readonly long[] Types = new long[(int)EItemType.MAX];
public static bool IsType(EItemType type1, EItemType type2)
{
if (0 > type1 || type1 >= EItemType.MAX)
throw new ArgumentException();
if (0 > type2 || type2 >= EItemType.MAX)
throw new ArgumentException();
var a = Types[(int) type1];
var b = Types[(int) type2];
return (a & b)!=0;
}
private static long ToValue(EItemType type)
{
if (type >= EItemType.SINGLE)
return 0L;
var value = (int) type;
return value < 64 ? (1L << value) : 0L;
}
static ItemTypeUtil()
{
for (EItemType i = 0; i <= EItemType.SINGLE; ++i)
{
Types[(int) i] = ToValue(i);
}
//资源
Types[(int) EItemType.RESURCE] =
Types[(int) EItemType.Food] |
Types[(int) EItemType.Wood] |
Types[(int) EItemType.Iron] |
Types[(int) EItemType.Oil];
//碎片
Types[(int) EItemType.DEBRIS] =
Types[(int) EItemType.Cap_Debris] |
Types[(int) EItemType.Cloth_Debris] |
Types[(int) EItemType.Pant_Debris] |
Types[(int) EItemType.Shoe_Debris] |
Types[(int) EItemType.Weppon_Debris];
//技能书
Types[(int) EItemType.SKILL_BOOK] =
Types[(int) EItemType.Skill_Book_A] |
Types[(int) EItemType.Skill_Book_B] |
Types[(int) EItemType.Skill_Book_C];
}
}
通过代码可以看到,在static中,所有SIngle以上的类型都通过位移运算符塞进了long[]中,对应的64位的二进制就分别是,0001,0010,0100,1000等..这样的话 RESOURCE可以算出值为0000 1111,这样判断枚举中的某一个是否为RESOURCE的子集话只需要通过&运算判断值是否为零即可,举个例子
EItemType.Food & EItemType.RESURCE
0000 0001 & 0000 1111 = 0000 0001 != 0
EItemType.Cap_Debris & EItemType.RESURCE
0001 0000 & 0000 1111 = 0000 0000 == 0
可以得到 Food 是 RESOURCE 的子集,而Cap_Debris 不是
其实这里可以看到这种结构有一个问题,或者说是有一个缺陷,long 的最大位是64位,也就是说,如果枚举的内容大于64个之后,位移运算64位以后的值都为0,如果超过枚举内容大于64该怎么处理。
这里可以采用高位集合和低位集合,两个long[] 的方法来解决,也就是说枚举位数小于64的可以直接1< 代码如下 private static readonly long[] LoTypes = new long[(int)EWorldBuildingType.MAX];
private static readonly long[] HiTypes = new long[(int)EWorldBuildingType.MAX];
public static bool IsType(EItemType s, EItemType b)
{
if (0 > s || s >= EItemType.MAX)
throw new ArgumentException();
if (0 > b || b >= EItemType.MAX)
throw new ArgumentException();
var loS = LoTypes[(int)s];
var loB = LoTypes[(int)b];
if ((loS & loB) != 0)
return true;
var hiS = HiTypes[(int)s];
var hiB = HiTypes[(int)b];
if ((hiS & hiB) != 0)
return true;
return false;
}
private static long ToLoValue(EItemType type)
{
if (type >= EItemType.SINGLE)
return 0L;
var value = (int) type;
return value < 64 ? (1L << value) : 0L;
}
private static long ToHiValue(EItemType type)
{
if (type >= EItemType.SINGLE)
return 0L;
var value = (int) type;
return value < 64 ? 0L : 1L << (value - 64);
}
static ItemTypeUtil()
{
for (EItemType i = 0; i <= EItemType.SINGLE; ++i)
{
LoTypes[(int)i] = ToLoValue(i);
HiTypes[(int)i] = ToHiValue(i);
}
//------------低位------------------------------------
//资源
LoTypes[(int) EItemType.RESURCE] =
LoTypes[(int) EItemType.Food] |
LoTypes[(int) EItemType.Wood] |
LoTypes[(int) EItemType.Iron] |
LoTypes[(int) EItemType.Oil] |
LoTypes[(int) EItemType.Copper];
//碎片
LoTypes[(int) EItemType.DEBRIS] =
LoTypes[(int) EItemType.Cap_Debris] |
LoTypes[(int) EItemType.Cloth_Debris] |
LoTypes[(int) EItemType.Pant_Debris] |
LoTypes[(int) EItemType.Shoe_Debris] |
LoTypes[(int) EItemType.Weppon_Debris];
//技能书
LoTypes[(int) EItemType.SKILL_BOOK] =
LoTypes[(int) EItemType.Skill_Book_A] |
LoTypes[(int) EItemType.Skill_Book_B] |
LoTypes[(int) EItemType.Skill_Book_C];
//------------高位------------------------------------
//资源
HiTypes[(int) EItemType.RESURCE] =
HiTypes[(int) EItemType.Food] |
HiTypes[(int) EItemType.Wood] |
HiTypes[(int) EItemType.Iron] |
HiTypes[(int) EItemType.Oil] |
HiTypes[(int) EItemType.Copper];
//碎片
HiTypes[(int) EItemType.DEBRIS] =
HiTypes[(int) EItemType.Cap_Debris] |
HiTypes[(int) EItemType.Cloth_Debris] |
HiTypes[(int) EItemType.Pant_Debris] |
HiTypes[(int) EItemType.Shoe_Debris] |
HiTypes[(int) EItemType.Weppon_Debris];
//技能书
HiTypes[(int) EItemType.SKILL_BOOK] =
HiTypes[(int) EItemType.Skill_Book_A] |
HiTypes[(int) EItemType.Skill_Book_B] |
HiTypes[(int) EItemType.Skill_Book_C];
}