¿Por qué las máscaras de capa de Unity necesitan usar desplazamiento de bits?

10

Finalmente descubrí por qué mis máscaras de capa para mi código de colisión en el suelo no funcionaban. Estaba usando NameToLayer()para obtener la capa que necesitaba, pero las máscaras de capa usan desplazamiento de bits para establecer realmente el valor de la máscara de capa. Esto es extremadamente inusual y no veo ninguna razón por la cual esto no se maneje en el código detrás. ¿Por qué tenemos que usar un código como este?

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

cuando algo como esto:

mask = LayerMask.NameToLayer("Default");

tiene más sentido intuitivo y funciona de forma similar al resto de la API de Unity?

Avestruz Espacial
fuente
2
Usar la versión de cadena requiere más potencia de procesamiento. Sin mencionar que la cadena es internamente una matriz que es un tipo de referencia y se agrega al recolector de basura.
Krythic

Respuestas:

3

Esto es extremadamente eficiente. Eso es todo: comparar cadenas, ya que el ejemplo obvio es más lento por un factor de 10. Y los cálculos de física tienen que estar muy optimizados, por lo que es bueno que alguien que sabía lo que estaba sucediendo lo escribiera de esta manera.

Entonces, la pregunta obvia de seguimiento es: ¿por qué no está esto envuelto en un método auxiliar para manejar la conversión y el cambio de bits? Creo que en realidad nadie lo consiguió: he enrollado mi propia ingeniosa herramienta de ayuda y esa es la práctica común.

Jordan Georgiev
fuente
1
La elección correcta del diseño por parte del equipo de Unity hubiera sido utilizar un número entero como indexador, en lugar de una cadena. Me estremezco cuando pienso en lo loco que probablemente se va el recolector de basura con su implementación actual, sin mencionar las asignaciones de la matriz de cadenas.
Krythic
1
Absolutamente, cualquier matriz es mejor referenciada por enteros. Los enteros podrían fácilmente ser humanamente legibles por una simple enumeración.
Jordan Georgiev
Una implementación rápida y sucia funciona, pero para proyectos más grandes uso [Type Safe] ( assetstore.unity3d.com/en/#!/content/35903 ).
Jordan Georgiev
20

El uso de desplazamiento de bits le permite tener en cuenta varias capas en una operación física:

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

Sin un poco de desplazamiento, se le permitirá emitir en una sola capa. Si bien con el desplazamiento de bits, puede emitir en varias capas específicas:

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

También puede emitir rayos en todas las capas, excepto las específicas:

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

Si nos fijamos en el "Administrador de capas" en Unity, las capas se pueden ver como los índices de una matriz simple de una dimensión .


EDITAR: nunca lo había visto antes, pero la LayerMaskclase tiene una función de utilidad para obtener la máscara de capa "calculada" dados los nombres de las capas:

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

Suponer UserLayerA y UserLayerBson las capas décima y undécima. Estos tendrán un valor de capa de usuario de 10 y 11. Para obtener su valor de máscara de capa, sus nombres se pueden pasar a GetMask. El argumento puede ser una lista de sus nombres o una serie de cadenas que almacenan sus nombres. En este caso, el valor de retorno será 2 ^ 10 + 2 ^ 11 = 3072.

Enlace a la documentación: https://docs.unity3d.com/ScriptReference/LayerMask.GetMask.html

Hellium
fuente
2
Debería usar OR bit a bit en |lugar de la suma de enteros +al hacer la unión de máscaras, la suma de enteros puede producir un comportamiento inesperado.
wondra
1
Pero, de nuevo, podrían haberlo hecho internamente y haber proporcionado un método comoLayerMask.NamesToLayers(params string[] layerNames)
QBrute
Buen punto @wondra! ;) - Sí, podrían haber hecho este QBrute, pero es mucho más flexible usar la operación de desplazamiento de bits si desea cambiar dinámicamente la máscara de capa (agregar, quitar capa, invertir, ...)
Hellium
Las operaciones bit a bit también son extremadamente rápidas. Son una excelente manera de componer datos binarios grandes.
Gusdor
Sin embargo, esto realmente no responde a la pregunta de por qué el método no solo devuelve directamente una máscara de capa en lugar de un número de capa.
Cubic