我的问题可能看起来有点业余,但我无法在任何地方找到答案。不久之前,Minecraft的一位开发人员谈到了如何在游戏中存储门(link)。他说他们用4位存储。 2表示方向,1表示上部或下部,1表示打开或关闭。这让我想到你是怎么做到的。您会看到存储一个字节,因为一个ASCII字符是一个字节。但是,你不能只将一些字符写入一个只有一点的文件,因为字符不能只用一个位存储,它们存储为一个字节。我知道有点表示为1或0.然而,将1或0写入文件将为您提供4个字节而不是单个位。那怎么办?
感谢。
答案 0 :(得分:3)
这很可能是通过组合不同的二进制标志来完成的。为了能够给出清晰的解释,您必须了解数字如何按位表示。基本上,它就像十进制计数一样,唯一不同的是只有两个数字可用。下面是一个例子(二进制表示中的十进制数字0-16)。
Decimal Binary
0 0
1 1
2 10
3 11
4 100
5 101
6 110
7 111
8 1000
9 1001
10 1010
11 1011
12 1100
13 1101
14 1110
15 1111
16 10000
这正是您的计算机存储数字的方式。 你还必须得到一个关于逐位运算符的基本未知。 假设您有两行8位,如下所示:
10101010
01011111
如果使用按位或运算符组合这两行 - “|” - 如果第1行的位x为1或第2行的位x为1,则输出的位x为1.因此,在我们的示例中,结果将如下所示:
11111111
逐位和运算符(&)检查第1行的位x是否为1且第2行的位x是否为1。 在我们的例子中,这是输出:
00001010
逐位xor(异或)运算符(^)检查是否只有一行的位x为1。 我们的输出看起来像这样:
11110101
基本上Minecraft的开发人员所做的是他们定义了一些标志。
// this is just an example, not Minecraft's actual code
public static final byte ORIENTATION_SOUTH = 0; // 00000000
public static final byte ORIENTATION_NORTH = 1; // 00000001
public static final byte ORIENTATION_WEST = 2; // 00000010
public static final byte ORIENTATION_EAST = 3; // 00000011
public static final byte PART_UPPER = 4; // 00000100 - third bit is 1
public static final byte PART_LOWER = 0; // 00000000 - third bit is 0
public static final byte STATE_OPEN = 8; // 00001000 - fourth bit is 1
public static fianl byte STATE_CLOSED = 0; // 00000000 - fourth bit is 0
因此,如果他们想要一个门的上部朝西并且打开的门状态,他们会这样写:
byte state = ORIENTATION_WEST | PART_UPPER | STATE_OPEN;
按位,它看起来像这样:
00000010 | (orientation)
00000100 | (part)
00001000 (open or closed)
然后最终会:
00001110 (west, upper part, open)
虽然只使用了字节的前4位,但正如你所说,你不能只保存位。很可能整个字节都被保存了。
答案 1 :(得分:2)
你是对的,当你只需要存储一个位时就不能这样做:你必须保存至少一个字节。
但是,如果您有多个项目,每个项目少于一个字节,您可以在一个字节中打包多个项目。
以4位门为例,假设您要存储有关两扇门的信息。你需要8位,这是一个字节。您可以将第一个门保存在较低的四位中,将第二个门保存在较高的四位中。当您需要获取第一个门的状态时,通过应用twoDoorsInOneByte & 0x0F
操作来屏蔽第二个门:它会剥离字节的较高部分。当你需要第二扇门时,使用向左移位将其位移动到位:(twoDoorsInOneByte >> 4) & 0x0F
:它将高四位移动到高四位,并清除字节上半部分的位以防万一价值得到了扩大。
最后,在C中您还有另一种选择:您可以使用bit fields。当您希望将任意长度的元素打包成几个单词以节省空间时,这可能很有用。请注意,应该谨慎应用此技术,当节省相对较高,或者内存太稀疏时(例如,您正在为8位微控制器编写嵌入式代码)。
答案 2 :(得分:1)
定义:
DOOR_UP = 0x01
DOOR_LEFT = 0x02
DOOR_BIG = 0x04
DOOR_SMALL = 0x08
DOOR_RED = 0x10
DOOR_BLUE = 0x20
DOOR_GREEN = 0x40
如果你需要左,小,绿门写
def door := DOOR_LEFT or DOOR_SMALL or DOOR_GREEN (Z** or some generic language)
byte door = DOOR_LEFT | DOOR_SMALL | DOOR_GREEN; (C++)
检查门绿色“问”:
door & DOOR_GREEN
零意味着不是绿色。非零(实际上,DOOR_GREEN)表示绿门
增加:
你甚至可以在一个字节中打包0-7的两个数字。在ZX Spectrum(1982)中使用相同的思想来定义字符的颜色:
Xbbbfff (bbb - background color, fff - foreground color, X - for blink)
要在4上设置bkg color 5和fgd,请使用:
color = 5 << 3 | 4
要获得背景颜色:
( color >> 3 ) & mask(0x7) -> 5
如果每分钟制作游戏很重要。尽可能避免使用位操作:)
答案 3 :(得分:0)
虽然他们说他们使用了4位,但我知道他们实际上是将信息存储在一个字节中(这很容易创建,因为字节是原始数据类型)。
我不相信可以直接存储一个位,但我想你想知道虽然他们说他们使用4位,但这些位存储在一个字节中。
答案 4 :(得分:0)
几乎所有现代计算机都是字节可寻址的,这意味着你只能寻址(指向)一个字节的内存而不是更小的内存。所以在这种情况下,它们可能存储一个字节。为了得到他们关心的位,他们使用位操作来操作字节:
const int OPEN_CLOSE_BIT = 1 << 0;
const int UPPER_LOWER_BIT = 1 << 1;
byte doorByte = getByteFromSomewhere();
if (doorByte & UPPER_LOWER_BIT) {
// the door is in some state
}