Perché le maschere di livello Unity devono usare lo spostamento dei bit?


10

Ho finalmente capito perché le mie maschere di livello per il mio codice di collisione del terreno non funzionavano. Stavo usando NameToLayer()per ottenere il livello di cui avevo bisogno, ma le maschere di livello usano lo spostamento dei bit per impostare effettivamente il valore della maschera di livello. Questo è estremamente insolito e non vedo alcun motivo per cui questo non è gestito nel codice dietro. Perché dobbiamo usare un codice come questo:

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

quando qualcosa del genere:

mask = LayerMask.NameToLayer("Default");

ha un senso più intuitivo e funziona in modo simile al resto dell'API Unity?


2
L'uso della versione stringa richiede più potenza di elaborazione. Per non parlare della stringa è internamente un array che è un tipo di riferimento e viene aggiunto al Garbage Collector.
Krythic,

Risposte:


3

Questo è estremamente performante. Questo è tutto ciò che c'è da fare - confrontare le stringhe poiché l'esempio ovvio è più lento di un fattore 10. E i calcoli della fisica devono essere molto ottimizzati, quindi è bene che qualcuno che sapeva cosa sta succedendo lo abbia scritto in questo modo.

Quindi l'ovvia domanda di follow-up è: perché questo non è racchiuso in un metodo di supporto per gestire la conversione e lo spostamento dei bit. Penso che nessuno ci sia riuscito davvero - ho arrotolato la mia abile utilità di aiuto e questa è la pratica comune.


1
La scelta del progetto corretta da parte del team Unity sarebbe stata quella di utilizzare un numero intero come indicizzatore, anziché una stringa. Mi arrabbio quando penso a quanto follemente stia andando il garbage collector con la sua attuale implementazione, per non parlare delle allocazioni di array di stringhe.
Krythic,

1
Assolutamente - ogni array è meglio indicato da numeri interi. I numeri interi potrebbero facilmente diventare umanamente leggibili da un semplice enum.
Jordan Georgiev,

Un'implementazione veloce e sporca funziona, ma per progetti più grandi uso [Type Safe] ( assetstore.unity3d.com/en/#!/content/35903 ).
Jordan Georgiev,

20

L'uso dello spostamento dei bit consente di prendere in considerazione più livelli in un'unica operazione fisica:

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

Senza spostamento di bit, ti sarà permesso di effettuare il raycast in uno strato e solo uno. Con lo spostamento dei bit, puoi eseguire il raycast in più livelli specifici:

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

Puoi anche effettuare il raycast in tutti i livelli tranne quelli specifici:

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

Se guardi il "Gestore livelli" in Unity, i livelli possono essere visti come gli indici di un semplice array monodimensionale .


EDIT: non l'ho mai visto prima, ma la LayerMaskclasse ha una funzione di utilità per ottenere la maschera di livello "calcolata" dato i nomi dei livelli:

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

Supponiamo UserLayerAe UserLayerBsiano il decimo e l'undicesimo strato. Questi avranno valori User Layer di 10 e 11. Per ottenere il loro valore di maschera di livello i loro nomi possono essere passati in GetMask. L'argomento può essere un elenco dei loro nomi o una matrice di stringhe che memorizzano i loro nomi. In questo caso il valore restituito sarà 2 ^ 10 + 2 ^ 11 = 3072.

Link alla documentazione: https://docs.unity3d.com/ScriptReference/LayerMask.GetMask.html


2
È necessario utilizzare OR bit per bit |anziché l'aggiunta di numeri interi +quando si esegue l'unione di maschere, l'aggiunta di numeri interi può produrre comportamenti imprevisti.
Wondra,

1
Ma ancora una volta, avrebbero potuto farlo internamente e fornire un metodo del tipoLayerMask.NamesToLayers(params string[] layerNames)
QBrute,

Buon punto @wondra! ;) - Sì, avrebbero potuto fare questo QBrute, ma è molto più flessibile usare l'operazione di cambio bit se si desidera cambiare dinamicamente la maschera di livello (aggiungere, rimuovere livello, invertire, ...)
Hellium

Anche le operazioni bit a bit sono estremamente veloci. Sono un modo eccellente per comporre dati binari di grandi dimensioni.
Gusdor,

Questo in realtà non risponde alla domanda sul perché il metodo non restituisce semplicemente una maschera di livello invece di un numero di livello.
Cubico,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.