C#(游戏开发)枚举+按位与或运算的特殊用法(一)枚举的集合

这里记录一下在游戏开发中,系统设计及业务逻辑处理中可以用到的枚举的一些小技巧。

(一)枚举集合的判断处理

集合判断通常用于子集的判断,判断某个大类是否包含某个类型

假设当前我们有一个物品类型的枚举

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];
}

 

你可能感兴趣的:(unity,C#算法,Unity算法)