Чому маскам шару Unity потрібно використовувати зміщення бітів?


10

Я нарешті з'ясував, чому маски шару для мого колінного зіткнення не працюють. Я використовував NameToLayer()для отримання потрібного мені шару, але маски шару використовують бітове зміщення, щоб фактично встановити значення маски шару. Це надзвичайно незвично, і я не бачу причин, чому це не обробляється в коді позаду. Чому ми повинні використовувати такий код:

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

коли щось подібне:

mask = LayerMask.NameToLayer("Default");

має більш інтуїтивний сенс і працює аналогічно решті API Unity?


2
Використання рядкової версії вимагає більшої потужності для обробки. Не кажучи вже про рядок - це внутрішній масив, який є еталонним типом і додається до сміттєзбірника.
Krythic

Відповіді:


3

Це надзвичайно добре. Це все, що в цьому є - порівняння рядків як очевидного прикладу повільніше на 10 разів. І розрахунки з фізики повинні бути дуже оптимізованими, тому добре, що хтось, хто знав, що відбувається, написав це так.

Тож очевидним подальшим питанням є питання - чому це не зафіксовано в допоміжному методі для обробки конверсій та змінення бітів. Я думаю, що насправді ніхто не дістався до цього - я розкрутив власну вишукану поміч-помічник, і це звичайна практика.


1
Правильним вибором дизайну командою Unity було б використання цілого числа як індексатора, а не рядка. Мені здається, коли я замислююся про те, наскільки шалено збирається сміття з їх поточною реалізацією, не кажучи вже про виділення рядкових масивів.
Krythic

1
Абсолютно - будь-який масив найкраще посилається на цілі числа. Цілі люди могли легко зрозуміти людину простим перерахунком.
Джордан Георгієв,

Швидка та брудна реалізація працює, але для великих проектів я використовую [Type Safe] ( resourcestore.unity3d.com/en/#!/content/35903 ).
Джордан Георгієв,

20

Використання бітового зсуву дозволяє враховувати кілька шарів за одну фізичну операцію:

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

Без зсуву біт вам дозволить вещати в один і лише один шар. Перебуваючи при зміщенні бітів, ви можете вещати в декілька конкретних шарів:

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

Ви також можете транслювати в усі шари, крім конкретних:

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

Якщо ви подивитеся на "Менеджер шарів" в Unity, шари можна розглядати як показники простого одновимірного масиву .


EDIT: Я ніколи не бачив цього раніше, але LayerMaskклас має корисну функцію для отримання "обчисленої" маски шару з урахуванням назв шарів:

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

Припустимо, UserLayerAі UserLayerBце десятий та одинадцятий шари. Вони матимуть значення користувальницького шару 10 та 11. Для отримання значення їх маски шару їхні імена можна передати у GetMask. Аргументом може бути або список їх імен, або масив рядків, що зберігають їх імена. У цьому випадку значення повернення буде 2 ^ 10 + 2 ^ 11 = 3072.

Посилання на документацію: https://docs.unity3d.com/ScriptReference/LayerMask.GetMask.html


2
Ви повинні використовувати побітове АБО |замість додавання цілого числа +при створенні об'єднання масок, ціле додавання може спричинити несподівану поведінку.
wondra

1
Але знову ж таки, вони могли зробити це внутрішньо і запропонували такий метод, якLayerMask.NamesToLayers(params string[] layerNames)
QBrute

Гарна точка @wondra! ;) - Так, вони могли б зробити цю QBrute, але набагато гнучкіше використовувати операцію зміщення бітів, якщо ви хочете динамічно змінювати маску шару (додавання, видалення шару, інвертування, ...)
Гелліум

Побітні операції також надзвичайно швидкі. Вони є прекрасним способом складання великих двійкових даних.
Гусдор

Це насправді не відповідає на питання, чому метод не просто повертає маску шару, а не номер шару.
Кубік
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.