Pourquoi les masques de calque Unity doivent-ils utiliser le décalage de bits?

10

J'ai enfin compris pourquoi mes masques de calque pour mon code de collision au sol ne fonctionnaient pas. J'utilisais NameToLayer()pour obtenir le calque dont j'avais besoin, mais les masques de calque utilisent le décalage de bits pour définir la valeur du masque de calque. C'est extrêmement inhabituel et je ne vois aucune raison pour laquelle cela n'est pas géré dans le code derrière. Pourquoi devons-nous utiliser un code comme celui-ci:

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

quand quelque chose comme ça:

mask = LayerMask.NameToLayer("Default");

est plus intuitif et fonctionne de manière similaire au reste de l'API Unity?

Autruche spatiale
la source
2
L'utilisation de la version chaîne prend plus de puissance de traitement. Sans oublier que la chaîne est en interne un tableau qui est un type de référence et est ajouté au garbage collector.
Krythic

Réponses:

3

C'est extrêmement performant. C'est tout ce qu'il y a à faire - comparer les chaînes comme l'exemple évident est plus lent d'un facteur 10. Et les calculs physiques doivent être très optimisés, il est donc bon que quelqu'un qui savait ce qui se passe l'écrive de cette façon.

Donc, la question de suivi évidente est - pourquoi n'est-ce pas enveloppé dans une méthode d'aide pour gérer la conversion et le décalage de bits. Je pense que personne n'y est vraiment parvenu - j'ai créé mon propre utilitaire d'assistance astucieux et c'est la pratique courante.

Jordan Georgiev
la source
1
Le choix de conception correct par l'équipe Unity aurait été d'utiliser un entier comme indexeur, au lieu d'une chaîne. Je grince des dents quand je pense à la folie du ramasse-miettes avec leur implémentation actuelle, sans parler des allocations de tableaux de chaînes.
Krythic
1
Absolument - tout tableau est mieux référencé par des entiers. Les nombres entiers pourraient facilement devenir humainement lisibles par une simple énumération.
Jordan Georgiev
Une implémentation rapide et sale fonctionne, mais pour les projets plus gros, j'utilise [Type Safe] ( assetstore.unity3d.com/en/#!/content/35903 ).
Jordan Georgiev
20

L'utilisation du décalage de bits vous permet de prendre en compte plusieurs couches en une seule opération physique:

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

Sans décalage de bit, vous seriez autorisé à diffuser des rayons en une seule couche et une seule. Avec le décalage de bits, vous pouvez diffuser des rayons en plusieurs couches spécifiques:

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

Vous pouvez également diffuser des rayons dans toutes les couches sauf celles spécifiques:

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

Si vous regardez le "Gestionnaire de calques" dans Unity, les calques peuvent être considérés comme les indices d'un simple tableau à une dimension .


EDIT: Je ne l'ai jamais vu auparavant, mais le LayerMask classe a une fonction utilitaire pour obtenir le masque de calque "calculé" étant donné les noms des calques:

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

Supposer UserLayerA que ce UserLayerBsont les dixième et onzième couches. Ceux-ci auront une valeur de couche utilisateur de 10 et 11. Pour obtenir leur valeur de masque de couche, leurs noms peuvent être passés dans GetMask. L'argument peut être soit une liste de leurs noms, soit un tableau de chaînes stockant leurs noms. Dans ce cas, la valeur de retour sera 2 ^ 10 + 2 ^ 11 = 3072.

Lien vers la documentation: https://docs.unity3d.com/ScriptReference/LayerMask.GetMask.html

Hellium
la source
2
Vous devez utiliser OR |au niveau du bit au lieu de l'ajout d'entiers +lors de l'union des masques, l'ajout d'entiers peut produire un comportement inattendu.
Wondra
1
Mais là encore, ils auraient pu le faire en interne et fournir une méthode commeLayerMask.NamesToLayers(params string[] layerNames)
QBrute
Bon point @wondra! ;) - Oui, ils auraient pu faire ce QBrute, mais il est beaucoup plus flexible d'utiliser l'opération de décalage de bit si vous voulez changer dynamiquement le masque de calque (ajouter, supprimer un calque, inverser, ...)
Hellium
Les opérations au niveau du bit sont également extrêmement rapides. Ils sont un excellent moyen de composer de grandes données binaires.
Gusdor
Cela ne répond pas vraiment à la question de savoir pourquoi la méthode ne renvoie pas simplement un masque de calque au lieu d'un numéro de calque.
Cubic