Por que as máscaras de camada do Unity precisam usar a mudança de bits?

10

Finalmente descobri por que minhas máscaras de camada para o meu código de colisão no solo não estavam funcionando. Eu estava usando NameToLayer()para obter a camada de que precisava, mas as máscaras de camada usam deslocamento de bits para realmente definir o valor da máscara de camada. Isso é extremamente incomum e não vejo nenhuma razão para que isso não seja tratado no código por trás. Por que temos que usar código como este:

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

quando algo assim:

mask = LayerMask.NameToLayer("Default");

faz mais sentido intuitivo e funciona de maneira semelhante ao restante da API do Unity?

Avestruz do espaço
fonte
2
O uso da versão de cadeia exige mais poder de processamento. Sem mencionar que a string é internamente uma matriz que é um tipo de referência e é adicionada ao coletor de lixo.
Krythic

Respostas:

3

Isso é extremamente eficiente. É tudo o que existe - comparar strings, pois o exemplo óbvio é mais lento em um fator de 10. E os cálculos de física precisam ser muito otimizados, por isso é bom que alguém que sabia o que está acontecendo o tenha escrito dessa maneira.

Portanto, a pergunta óbvia de acompanhamento é: por que isso não está envolvido em um método auxiliar para lidar com a conversão e a mudança de bits? Eu acho que ninguém realmente conseguiu - criei meu próprio utilitário auxiliar bacana e essa é a prática comum.

Jordan Georgiev
fonte
11
A escolha correta do design pela equipe do Unity seria usar um número inteiro como indexador, em vez de uma string. Eu me arrepio quando penso no quão louco o coletor de lixo provavelmente está indo com sua implementação atual, sem mencionar as alocações de array de string.
Krythic #
11
Absolutamente - qualquer matriz é melhor referenciada por números inteiros. Inteiros podem facilmente se tornar humanamente legíveis por um enum simples.
Jordan Georgiev
Uma implementação rápida e suja funciona, mas para projetos maiores eu uso o [Type Safe] ( assetstore.unity3d.com/en/#!/content/35903 ).
Jordan Georgiev
20

O uso de deslocamento de bits permite levar em consideração várias camadas em uma operação física:

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

Sem troca de bits, você seria autorizado a transmitir raios em uma camada e apenas uma. Enquanto com a mudança de bits, você pode transmitir em raios em várias camadas específicas:

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

Você também pode transmitir raios em todas as camadas, exceto as específicas:

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

Se você olhar para o "Gerenciador de camadas" no Unity, as camadas poderão ser vistas como os índices de uma matriz simples de uma dimensão .


EDIT: Eu nunca vi isso antes, mas a LayerMaskclasse tem uma função de utilitário para obter a máscara de camada "computada", dados os nomes das camadas:

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

Suponha UserLayerAe UserLayerBseja a décima e a décima primeira camadas. Eles terão um valor de camada de usuário de 10 e 11. Para obter o valor da máscara de camada, seus nomes podem ser passados ​​para o GetMask. O argumento pode ser uma lista de seus nomes ou uma matriz de cadeias armazenando seus nomes. Nesse caso, o valor de retorno será 2 ^ 10 + 2 ^ 11 = 3072.

Link para a documentação: https://docs.unity3d.com/ScriptReference/LayerMask.GetMask.html

Hellium
fonte
2
Você deve usar OR bit a bit em |vez de adição de número inteiro +ao fazer a união de máscaras, a adição de número inteiro pode produzir um comportamento inesperado.
Wondra
11
Mas, novamente, eles poderiam ter feito isso internamente e forneceram um método comoLayerMask.NamesToLayers(params string[] layerNames)
QBrute 27/10/16
Bom ponto @wondra! ;) - Sim, eles poderiam ter feito isso QBrute, mas é muito mais flexível usar a operação de desvio de bits se você quiser alterar dinamicamente a máscara de camada (adicionando, removendo, invertendo, ...)
Hellium
As operações bit a bit também são extremamente rápidas. Eles são uma excelente maneira de compor grandes dados binários.
Gusdor 27/10
Isso realmente não responde à pergunta de por que o método não retorna apenas uma máscara de camada em vez de um número de camada.
Cubic