XNA中的位标志

近日在研究StunEngine引擎时,遇到了一些看不懂的代码,搜索后才发现原来只是简单的位运算,没想到还能用在这种场合,具体信息可见msdn上的http://msdn.microsoft.com/zh-cn/library/6a71f45d(VS.80).aspx。

这篇文章来自于XNA UK User Group,http://xna-uk.net/,原文地址:http://xna-uk.net/blogs/randomchaos/archive/2010/03/24/bit-flags-in-xna.aspx,下面是译文。

什么是Bit Flags,它实际上是一种在一个变量中存储多个值的方法。上一次我使用Bit Flags好像是在几年前帮一个朋友编写一个MUD的时候,如果我没记错的话,我使用位运算存储玩家状态,他/她是否处于站立、行走、奔跑或游泳状态,还用在房间的位置,房间是否有一面向北的墙或天花板。

那么如何在C#中使用它们,为什么我们使用的值有限制?

首先你必须知道逻辑位运算(http://en.wikipedia.org/wiki/Bitwise_operation,logical bitwise operators)和它的工作原理,我们将使用它们在一个变量中测试和设置位,这个可以帮你理解为何我们只能使用特定的值。在计算机中整数值是由一个二进制值表示的,即一组0和1,让我们看一下数字0到10的二进制值是什么:

整数值 二进制值
0 00000000
1 00000001
2 00000010
3 00000011
4 00000100
5 00000101
6 00000110
7 00000111
8 00001000
9 00001001
10 00001010

上面的表格我展示了8位数字的二进制代码,即有8个位可以用来代表一个值。我们看到数字8的二进制代码是00001000,所以要表示数字8,我们只需将第四个位设置为1其他为0,8位数字最大为255。如果我们有一个整数发现它的第四个位是1,那么这个整数是8吗?不是,看一下9和10,它们的第四个位也是1,这就是为什么我们只能使用特定值的原因,这些值必须是2的整数次幂。

如果看一下下面的表格,你会发现只有2的整数次幂的数字,这样就不会有位交叉了:

整数值 二进制值
1 00000000 00000000 00000000 00000001
2 00000000 00000000 00000000 00000010
4 00000000 00000000 00000000 00000100
8 00000000 00000000 00000000 00001000
16 00000000 00000000 00000000 00010000
32 00000000 00000000 00000000 00100000
64 00000000 00000000 00000000 01000000
128 00000000 00000000 00000000 10000000
256 00000000 00000000 00000001 00000000
512 00000000 00000000 00000010 00000000
1024 00000000 00000000 00000100 00000000
2048 00000000 00000000 00001000 00000000
4096 00000000 00000000 00010000 00000000
8192 00000000 00000000 00100000 00000000
16384 00000000 00000000 01000000 00000000
32768 00000000 00000000 10000000 00000000
65536 00000000 00000001 00000000 00000000
131072 00000000 00000010 00000000 00000000
262144 00000000 00000100 00000000 00000000
524288 00000000 00001000 00000000 00000000
1048576 00000000 00010000 00000000 00000000
2097152 00000000 00100000 00000000 00000000
4194304 00000000 01000000 00000000 00000000
8388608 00000000 10000000 00000000 00000000
16777216 00000001 00000000 00000000 00000000
33554432 00000010 00000000 00000000 00000000
67108864 00000100 00000000 00000000 00000000
134217728 00001000 00000000 00000000 00000000
268435456 00010000 00000000 00000000 00000000
536870912 00100000 00000000 00000000 00000000
1073741824 01000000 00000000 00000000 00000000
2147483648 10000000 00000000 00000000 00000000

现在我们有了一个32位的二进制值表格表示flags,它们不会交叉。

我们如何设置并测试这些位?这就需要用到逻辑位运算了。要设置一个值的位,我们可以使用| (或)运算符,它会根据你的需要设置一个值中的位:

int value2 = 2;
int value4 = 4;
int value8 = 8; 
int value = 0;

value = value2 |value8; 

上面的操作中value的二进制代码为:00001010即整数10(电脑对二进制数进行了求和运算!) ,现在我们在一个变量中存储了两个值,value2表示武器是否已经被装备,而value8表示武器是否已经加载了弹药。如果我们调用 | 运算符你能获得相同的值(value2和value8),一旦位被设置就不会改变。

那么我们如何测试一个值是否被设置?这可以通过使用 & (与) 运算符做到,这个运算会进行如下所示的测试:

int value2 = 2; 
int value4 = 4;
int value8 = 8;
int value = 0;

value = value2 | value8; 

int result = 0;
result = value & value2; 
result = value & value4; 

第一次我们测试value2存储在value中 ,这个value会赋值为value2,第二次我们测试不在value中的value4,这会让result为0。

如果我们只想打开或关闭一个位应该如何处理呢?这需要用到^ (异或)运算,这个运算会将1设置为0或将0设置为1,就好像一个电灯开关一样:

int value2 = 2; 
int value4 = 4; 
int value8 = 8; 
int value = 0; 

value ^= value2; 
value ^= value2; 

第一次调用让value包含value2,第二次调用从value中移除value2。

我制作了一个简单的XNA项目使用上面的操作符,在这个项目中我使用一个枚举表示bit flags:

public enum GunStates : int
{
    Empty = 1, 
    Loading = 2,
    Shooting = 4,
    Equiped = 8, 
    Loaded = 16 
} 

注意我将枚举强类型化为一个整数,你也可以使用short, long, byte或其他类型,我使用的设置和检查状态的方法如下所示:

public void SetGunState(GunStates stateSet) 
{
    state ^= stateSet;
}

public bool CheckGunState(GunStates stateChk) 
{
    return (state & stateChk) == stateChk; 
}

你还可以看一下位偏移(左移位<<和右移位>>),value2 << 1会将value2中的位左移一位,结果是4,如果将value2重新赋值为2并进行value2 << 2操作,则values2中的所有位左移2位,结果为8,要将value2重新设置为2可进行value2 >> 2的操作。

源代码GenericXNABitFlags.zip下载。

文件下载(已下载 1259 次)

发布时间:2010/4/2 下午1:36:59  阅读次数:6186

2006 - 2024,推荐分辨率 1024*768 以上,推荐浏览器 Chrome、Edge 等现代浏览器,截止 2021 年 12 月 5 日的访问次数:1872 万 9823 站长邮箱

沪 ICP 备 18037240 号-1

沪公网安备 31011002002865 号