再会!
我了解Unity的工作原理,我观看教程和一些脚本,有时我会遇到类似这样的结构1 << layer,其中layer是一个整数。我经常在与物理相关的方法中看到这一点,例如Raycast:
public int groundLayer = 5;
void SomeMethod() {
// do smth...
if (Physics.RaycastAll(transform.position, transform.forward, 100.0f, 1 << groundLayer).Length > 0) {
...
}
// do smth...
}
不仅限于物理学:
LayerMask Collisionmask;
int layer = 5;
void SomeMethod() {
// do smth...
if ((Collisionmask.value & (1 << layer)) == 0) {
...
}
// do smth...
}
我读到这些是某种面具。他们指向图层。但是不明白这些mask是什么,怎么用,和layers有什么关系?什么是1 << layer,例如?
有人可以详细解释吗?谢谢你。
储备爆米花和可乐(馅饼和茶)。它会很长,但内容丰富。))
它是什么,为什么?
在Unity中,众所周知(或不仅是每个人)都知道,有层(layers)。您可以在文档中刷新您的记忆(如果您不知道,请阅读并熟悉)。它们以不同的方式使用。例如,
2D在他们的帮助下,您可以指定和分离背景/中间/前景。有些会在后面,有些会在前面。在更复杂的游戏中,可能会有更多的层,并且可以通过这些层对对象进行分组。例如,您可以为敌对 NPC 和其他人创建一个图层并NPC从中选择一个图层Enemies。在一般情况下,使用
layerMask(mask) 进行操作可以找出被选中的对象 (GameObject) 是否在指定层中(无论它是什么类型的对象以及如何检查都无关紧要)。根据检查的结果,执行预期的操作。例如,考虑
Raycast。如果我们转向文档,我们可以看到该方法如下所示:选项之一:
int layerMask = DefaultRaycastLayers。它是这样工作的:光束从某个方向的某个点发射(比方说这在远处是如此神奇),光束落在某种障碍物(物体)上,例如,如果这个物体在层Enemies,打它。(Collisionmask.value & (1 << layer)) == 0下面我们讲一个例子。但其本质是一样的:因面具而确定归属 > 做某事取决于……我希望本质是清楚的,让我们继续。
这个怎么运作。
Unity中的层数:32。它们从 0 到 31 编号。
LayerMask(掩码) - 表示为 32 位整数:为了更好的可读性,我将每 4 位分开。
掩码使用其 32 位来表示各种标志(对象的状态,例如:1 - 启用,0 - 禁用)。在这种特殊情况下,每个标志(位)代表一个特定的层。我们先拿前8层进行分析,记下每一层的二进制表示(第一位(最低位)在右边)。
这就是层的二进制表示形式。如您所见,特定层由一个特定位定义。
现在让我们试着用一个例子来理解
if ((Collisionmask.value & (1 << layer)) == 0)。我们看到一个
layer整数变量。这个变量是层数(0、1、2、3、4 ...),不是十进制也不是二进制表示。Collisionmask检查器中是一个包含图层的下拉列表:Collisionmask.value反过来,它是所选层组合的二进制表示(因为我们不能选择一个层,而是多个层)。为了便于理解:例如,如果我们要为层 #2 和 #5 创建掩码,则二进制表示将如下所示:或者例如图层 #1、#2、#5、#6 将是:
我们想要什么?我们想知道我们正在检查的层是否包含在这个掩码中
layer?并以此为依据,做点什么。在上面的例子中,如果我们在第 5 层的对象不包含在指定的掩码中,我们想进入一个条件并做一些事情。比方说
LayerMask = 0110 0110; // #1,#2,#5,#6,我们层的编号int layer = 5;有必要将第 5 层带入其二进制表示,对应于层。让我们看看上表。
<<第 5 层的十进制表示形式为 32。反过来,二进制表示形式为 0010 0000。它是通过应用相对于最低有效位 (0000 0001) 恰好 5 个值的按位左移运算符获得的(太棒了! ). 向左移动 5 次:如您所见,数字 0010 0000 结果出来了,它确实包含在我们的蒙版
0110 0110中,因为蒙版在右侧的位置编号 6 中包含一个 1,而第 5 层在相同位置也有一个。如果您不相信我的话,那么检查起来很容易:您需要在掩码和被检查的值之间执行按位乘法(按位与“&”)。顺便说一句,这是在行中完成的Collisionmask.value & (1 << layer)我们看到面具中包含什么。如果不包含,则按位乘法将得出结果 0。作为证明示例,我们可以检查此掩码中是否包含第 7 层。将最低有效位向左移动 7 位:
我们得到 1000 0000。检查
我们看到 0。不包括在内。因为它不包括在内,所以我们上面的条件被触发:
所以我们进入条件并做我们需要的。这就是我们要找的。
添加 1
除了检查特定图层是否包含在蒙版中之外,您还可以检查除指定图层之外的所有图层。可以说,您只需要使用反转运算符 (~)。它将操作数 0 的位表示更改为 1,将 1 更改为 0。因此 ~00000010 将是 11111101,它将测试除 #2 之外的所有层。如果要排除多个图层,则需要使用“或”运算符组合蒙版:
补充2
事实上,并不总是需要写
1 << что-то. 例如,Raycast您可以传入 parameterCollisionmask.value,其中Collisionmask它的类型为LayerMask,它又看起来像检查器中的下拉列表(参见图 2)。很舒服。另外,不要硬编码数字,即 不要写
1 << 7or1 << 5,因为 你可以忘记 5 和 7 是什么。为了找出所需的层数,你可以使用LayerMask.NameToLayer,例如:和“组”面具一样:
补充3
事实上,这种构造
1 << ...不仅存在于 Unity 中。这是一般编程中众所周知的做法。例如,一个制造商有一个产品,一个应用程序,它为其他程序员提供了一个 API。API 可以有各种访问限制。程序员指定他想要访问的掩码,然后在应用程序服务器上检查它,如果掩码不匹配,它会发出警告或其他内容。Vkontakte 及其API 访问权限的最简单示例
那里指示了十进制表示,但它并没有改变本质。