Dlaczego maski warstw Unity wymagają przesunięcia bitów?

10

W końcu zorientowałem się, dlaczego moje maski warstw dla mojego kodu kolizji z ziemią nie działają. Używałem, NameToLayer()aby uzyskać potrzebną warstwę, ale maski warstw używają przesunięcia bitowego, aby faktycznie ustawić wartość maski warstwy. Jest to niezwykle nietypowe i nie widzę żadnego powodu, dla którego nie byłoby to obsługiwane w kodzie z tyłu. Dlaczego musimy używać takiego kodu:

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

gdy coś takiego:

mask = LayerMask.NameToLayer("Default");

ma bardziej intuicyjny sens i działa podobnie do reszty interfejsu API Unity?

Kosmiczny struś
źródło
2
Korzystanie z wersji łańcuchowej wymaga większej mocy obliczeniowej. Nie wspominając o tym, że łańcuch jest wewnętrznie tablicą, która jest typem referencyjnym i jest dodawana do śmietnika.
Krythic

Odpowiedzi:

3

To jest niezwykle wydajne. To wszystko - porównywanie ciągów, ponieważ oczywisty przykład jest wolniejszy dziesięciokrotnie. A obliczenia fizyki muszą być bardzo zoptymalizowane, więc dobrze, że ktoś, kto wiedział, co się dzieje, napisał to w ten sposób.

Zatem oczywistym pytaniem jest - dlaczego nie jest to zawarte w metodzie pomocniczej do obsługi konwersji i zmiany bitów. Myślę, że tak naprawdę nikt tego nie dotarł - zwinąłem swoją własną sprytną pomocniczkę i jest to powszechna praktyka.

Jordan Georgiev
źródło
1
Prawidłowym wyborem projektu przez zespół Unity byłoby użycie liczby całkowitej jako indeksu zamiast ciągu. Kulę się, gdy myślę o tym, jak szalony jest śmieciarz przy obecnej implementacji, nie wspominając już o przydziałach tablic łańcuchów.
Krythic,
1
Oczywiście - każda tablica jest najlepiej przywoływana przez liczby całkowite. Liczby całkowite mogą łatwo stać się czytelne dla człowieka za pomocą prostego wyliczenia.
Jordan Georgiev,
Szybka i brudna implementacja działa, ale do większych projektów używam [Type Safe] ( assetstore.unity3d.com/en/#!/content/35903 ).
Jordan Georgiev,
20

Korzystanie z przesunięcia bitowego pozwala uwzględnić wiele warstw w jednej operacji fizycznej:

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

Bez przesuwania bitów, możesz raycastować w jednej warstwie i tylko w jednej. Podczas przesuwania bitów możesz raycast na wielu określonych warstwach:

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

Możesz także raycastować na wszystkich warstwach oprócz określonych:

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

Jeśli spojrzysz na „Menedżera warstw” w Unity, warstwy mogą być postrzegane jako wskaźniki prostej tablicy jednowymiarowej .


EDYCJA: Nigdy wcześniej go nie widziałem, ale LayerMaskklasa ma funkcję użyteczną do uzyskania „obliczonej” maski warstwy, biorąc pod uwagę nazwy warstw:

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

Załóżmy UserLayerAi UserLayerBsą dziesiątą i jedenastą warstwą. Będą miały wartości warstwy użytkownika 10 i 11. Aby uzyskać wartość maski warstwy, ich nazwy można przekazać do GetMask. Argumentem może być lista ich nazw lub tablica ciągów przechowujących ich nazwy. W takim przypadku zwracana wartość będzie wynosić 2 ^ 10 + 2 ^ 11 = 3072.

Link do dokumentacji: https://docs.unity3d.com/ScriptReference/LayerMask.GetMask.html

Hel
źródło
2
Podczas tworzenia unii masek powinieneś używać bitowego OR |zamiast dodawania liczb +całkowitych, dodawanie liczb całkowitych może powodować nieoczekiwane zachowanie.
wondra
1
Ale z drugiej strony mogli to zrobić wewnętrznie i udostępnić metodę typuLayerMask.NamesToLayers(params string[] layerNames)
QBrute,
Dobry punkt @wondra! ;) - Tak, mogliby zrobić to QBrute, ale o wiele bardziej elastyczna jest operacja przesunięcia bitów, jeśli chcesz dynamicznie zmieniać maskę warstwy (dodawanie, usuwanie warstwy, odwracanie, ...)
Hellium
Operacje bitowe są również niezwykle szybkie. Są doskonałym sposobem na połączenie dużych danych binarnych.
Gusdor
To tak naprawdę nie odpowiada na pytanie, dlaczego metoda nie zwraca po prostu maski warstwy zamiast numeru warstwy.
Cubic