为什么Unity图层蒙版需要使用位移?


10

我终于弄清楚了为什么我的地面碰撞代码的图层蒙版不起作用。我曾经NameToLayer()用来获取所需的图层,但是图层蒙版使用位移来实际设置图层蒙版值。这是非常不寻常的,我看不出任何原因都无法在后面的代码中处理。为什么我们必须使用如下代码:

mask = 1 << LayerMask.NameToLayer("Default");

当这样的事情:

mask = LayerMask.NameToLayer("Default");

更加直观,并且与Unity API的其余部分类似?


2
使用字符串版本需要更多处理能力。更不用说该字符串在内部是一个数组,它是一种引用类型,并被添加到垃圾收集器中。
Krythic

Answers:


3

这是非常出色的。这就是全部内容-比较字符串,因为显而易见的示例将速度减慢了10倍。而且物理计算必须非常优化,因此,知道发生了什么事情的人以这种方式编写它是一件好事。

因此,显而易见的后续问题是-为什么不将其包装在帮助程序方法中以处理转换和位移位。我认为没有人真正做到这一点-我汇总了自己的漂亮的助手实用程序,这是常见的做法。


1
Unity团队的正确设计选择是使用整数而不是字符串作为索引器。当我想到垃圾收集器在当前的实现中可能会变得多么疯狂时,我会感到畏缩,更不用说字符串数组分配了。
Krythic

1
绝对-最好用整数引用任何数组。一个简单的枚举可以很容易地使整数成为人类可读的。
Jordan Georgiev

快速而肮脏的实现是可行的,但是对于较大的项目,我使用[类型安全](assetstore.unity3d.com/en/#!/content/35903)。
乔丹·乔治(Jordan Georgiev)

20

使用移位可以使您在一个物理操作中考虑多个层:

 Physics.Raycast(ray, out hitInfo, Mathf.Infinity, layerMask )

如果不进行移位,则只允许您一层广播。在进行位移的同时,您可以在多个特定层中进行射线广播:

layerMask = (1 << LayerMask.NameToLayer("MyLayer1")) | (1 << LayerMask.NameToLayer("MyLayer2")) ;

您还可以在特定图层之外的所有图层中进行光线投射:

layerMask = (1 << LayerMask.NameToLayer("MyLayer1")) | (1 << LayerMask.NameToLayer("MyLayer2")) ;
layerMask = ~layerMask;

如果您在Unity中查看“图层管理器​​”,则可以将图层视为简单一维数组的索引


编辑:我之前从未见过,但是LayerMask该类具有实用程序功能,可以根据给定的层名称获取“计算的”层掩码:

Debug.Log( LayerMask.GetMask("UserLayerA", "UserLayerB") ) ;

假设UserLayerAUserLayerB是第十和第十一层。它们的用户层值分别为10和11。要获取其层掩码值,可以将其名称传递给GetMask。参数可以是其名称的列表,也可以是存储其名称的字符串数组。在这种情况下,返回值将是2 ^ 10 + 2 ^ 11 = 3072。

链接到文档:https : //docs.unity3d.com/ScriptReference/LayerMask.GetMask.html


2
进行掩码的并集时,应使用按位或|而不是整数加法+,整数加法可能会产生意外的行为。
温德拉

1
但是话又说回来,他们本可以在内部完成,并提供了类似的方法LayerMask.NamesToLayers(params string[] layerNames)
-QBrute

好点@wondra!;)-是的,他们可以做这个QBrute,但是如果您想动态更改图层蒙版(添加,删除图层,反转等),则可以使用位偏移操作更加灵活
Hellium

按位运算也非常快。它们是合成大型二进制数据的绝佳方法。
Gusdor

这并不能真正回答为什么该方法不能直接向上返回图层蒙版而不是图层编号的问题。
立方
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.