Почему маски слоя 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

Hellium
источник
2
При объединении масок следует использовать побитовое ИЛИ |вместо целочисленного сложения +, целочисленное сложение может привести к неожиданному поведению.
Wondra
1
Но опять же, они могли бы сделать это внутренне и предоставить такой метод, какLayerMask.NamesToLayers(params string[] layerNames)
QBrute
Хороший вопрос @ Wondra! ;) - Да, они могли бы сделать это QBrute, но гораздо более гибко использовать операцию сдвига битов, если вы хотите динамически изменять маску слоя (добавление, удаление слоя, инвертирование, ...)
Hellium
Побитовые операции также чрезвычайно быстры. Они являются отличным способом объединения больших двоичных данных.
Gusdor
Это на самом деле не отвечает на вопрос, почему метод не просто возвращает маску слоя вместо номера слоя.
Куб