Почему маски слоя Unity должны использовать сдвиг битов?


10

Я наконец понял, почему мои маски слоев для моего кода столкновения с землей не работают. Я использовал, NameToLayer()чтобы получить нужный мне слой, но маски слоя используют сдвиг битов, чтобы фактически установить значение маски слоя. Это чрезвычайно необычно, и я не вижу причин, почему это не обрабатывается в коде позади. Почему мы должны использовать такой код:

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

когда как то так

mask = LayerMask.NameToLayer("Default");

имеет более интуитивный смысл и работает аналогично остальной части Unity API?


2
Использование строковой версии требует больше вычислительной мощности. Не говоря уже о том, что строка внутренне является массивом, который является ссылочным типом и добавляется в сборщик мусора.
— Krythic

Ответы:


3

Это чрезвычайно эффективно. Вот и все, что нужно - сравнение строк в качестве очевидного примера медленнее в 10 раз. И физические вычисления должны быть очень оптимизированы, поэтому хорошо, что кто-то, кто знал, что происходит, написал это таким образом.

Таким образом, очевидный последующий вопрос - почему это не обернуто во вспомогательный метод для обработки преобразования и сдвига битов. Я думаю, что на самом деле никто не дошел до этого - я свернул свою собственную полезную вспомогательную утилиту, и это обычная практика.


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

1
Абсолютно - на любой массив лучше всего ссылаться целыми числами. Целые числа могут легко стать понятными для человека простым перечислением.
— Джордан Георгиев

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

20

Использование сдвига битов позволяет учитывать несколько слоев в одной физической операции:

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

Без смещения битов вам будет разрешено осуществлять радиопередачу в одном слое и только в одном. В то время как со сдвигом битов, вы можете raycast в нескольких конкретных слоях:

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

Вы также можете выполнять Raycast на всех слоях, кроме определенных:

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

Если вы посмотрите на «Диспетчер слоев» в Unity, слои можно рассматривать как индексы простого одномерного массива .


РЕДАКТИРОВАТЬ: я никогда не видел его раньше, но у 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, но гораздо более гибко использовать операцию сдвига битов, если вы хотите динамически изменять маску слоя (добавление, удаление слоя, инвертирование, ...)
— Hellium

Побитовые операции также чрезвычайно быстры. Они являются отличным способом объединения больших двоичных данных.
— Gusdor

Это на самом деле не отвечает на вопрос, почему метод не просто возвращает маску слоя вместо номера слоя.
— Куб
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.