В инспекторе любого GameObject можно указать слой (layer). На каждый gameobject только один слой.
.png)
### Зачем нужны слои?
Обычно слои используются для разделения gameobject’ов на категории, такие как игроки, враги, объекты окружения и т.д.
Слои могут использоваться для различных целей в Unity,
например:
* Организация объектов в сцене по группам для лучшей навигации и управления
* Определение сложных условий столкновения и взаимодействия между объектами (Если использовать Engine Unity)
* Управление отображением объектов на определенных слоях в зависимости от настроек камеры
### Что под капотом у Layer?
Сам по себе layer (Слой) - это целочисленный идентификатор (int-тип), от 0 до 31. В Unity можно иметь до 32 слоев на один проект, 5 из которых зарезервированы под систему.
Слой можно создать только через инспектор (на самом деле и через код тоже, но код будет работать только в редакторе, а не в сборке игры)
##### Методы, связанные только с индексом слоя (без маски слоев)
Получение имени слоя по индексу слоя
```csharp
string objectLayerName = LayerMask.LayerToName(objectLayerIndex);
```
Наоборот.
Дальше, идет присваивание индекса слоя к GameObject.
```csharp
gameObject.layer = LayerMask.NameToLayer("MyLayer");
```
### Как работать со слоями?
Со слоями работают через битовую маску слоев (LayerMask)
LayerMask представляет собой int-число, где каждый бит соответствует определенному слою.
Обратите внимание! LayerMask хранится как десятичное число, однако с этим числом работают побитово!
##### Использование LayerMask
В коде Unity, LayerMask представлен классом LayerMask. Его можно использовать, чтобы создавать маски слоев, добавлять и удалять слои из маски, и проверять, включает ли маска слой.
Вот несколько примеров использования LayerMask в коде:
Вы можете создать LayerMask, используя метод LayerMask.GetMask(), который принимает имена слоев и возвращает соответствующую маску слоя.
```csharp
// создание маски слоев
LayerMask mask = LayerMask.GetMask("Player", "Enemy");
// добавление слоя в маску
mask |= LayerMask.GetMask("Environment");
// удаление слоя из маски
mask &= ~LayerMask.GetMask("Enemy");
// проверка наличия слоя в маске
if (mask.Contains(LayerMask.NameToLayer("Player")))
{
// выполняем действие
}
```
<br>
LayerMask обычно используется с физическими методами, такими как Physics.Raycast, Physics.OverlapSphere, Collider.Raycast и другими. Вы передаете маску слоя в качестве параметра, чтобы указать, на каких слоях должны производиться проверки.
```csharp
int layerMask = LayerMask.GetMask("Unit", "Ground", "Obstacles");
RaycastHit hit;
if (Physics.Raycast(ray, out hit, Mathf.Infinity, layerMask))
{
// Обработка столкновения
}
```
##### Настройка слоев
В Unity вы можете настроить слои в окне "Edit -> Project Settings -> Tags and Layers". Здесь вы можете добавлять новые слои или изменять существующие. У каждого GameObject можно выбрать слой, на котором он будет находиться, в инспекторе.
##### Битовые операции с LayerMask
Поскольку LayerMask представляет собой целочисленное значение, вы можете выполнять битовые операции над ними, такие как объединение (OR), пересечение (AND) или инверсия (NOT). Это может быть полезно, если вы хотите создать динамические маски слоев или исключить определенные слои из маски.
Например, если вы хотите объединить две маски слоев, вы можете использовать операцию OR (|):
```csharp
int layerMask1 = LayerMask.GetMask("Unit");
int layerMask2 = LayerMask.GetMask("Ground");
int combinedLayerMask = layerMask1 | layerMask2;
```
Если вы хотите исключить определенный слой из маски слоев, вы можете использовать операцию AND (~):
```csharp
int layerMask = LayerMask.GetMask("Unit", "Ground");
int excludeGroundLayer = ~(1 << LayerMask.NameToLayer("Ground"));
int finalLayerMask = layerMask & excludeGroundLayer;
```
В этом примере finalLayerMask будет содержать только слой "Unit", поскольку слой "Ground" исключен из исходной маски слоев.
##### LayerMask в инспекторе
Поле с типом LayerMask можно отобразить в инспекторе.
```csharp
[SerializeField] private LayerMask layer;
```
Как выглядит поле в инспекторе (можно выбирать несколько значений)
-7.png)
Выбранные слои записываются как int.
Хоть информация и записана в int, но записана она в двоичной системе. Int имеет размер в 32 бита, поэтому в Unity есть лимит слоев, нельзя иметь больше 32 слоев. Каждый бит (0 или 1) означает включен или выключен порядковый слой.
00000000000000000000000000000001 - Включен только первый слой (Default)
### Что такое маска?
Побитовая маска (bitmask) в программировании - это последовательность битовых значений, которая используется для выбора или отбрасывания определенных битов в других последовательностях значений. Маски обычно используются в операциях логического И, логического ИЛИ или битовых сдвигов, чтобы отфильтровать или настроить значения битов.
В контексте LayerMask в Unity, маска слоев используется для выбора определенных слоев в различных операциях. Маска слоев представляет собой 32-битную последовательность, где каждый бит соответствует определенному слою в Unity. Например, если мы хотим выбрать первый и второй слои из 32 возможных слоев, мы можем установить первые два бита в маске слоев:
```
0000 0000 0000 0000 0000 0000 0000 0011
```
В данном примере первые два бита установлены в единицы, что соответствует выбранным слоям.
GPT-3.5
<br>
Документация
[layer](https://docs.unity3d.com/2021.3/Documentation/ScriptReference/GameObject-layer.html)
[LayerMask](https://docs.unity3d.com/2021.3/Documentation/ScriptReference/LayerMask.html)
[Релевантная статья](https://matteolopiccolo.medium.com/unity-layermask-2b4ace33b52a)
##### Можно написать так?
##### Physics.Raycast(ray, out hitInfo, maxDistance, LayerMask.NameToLayer("Unit"));
Нет, неправильно использовать LayerMask.NameToLayer() в данном случае. Метод NameToLayer возвращает <u>индекс слоя</u>, а не <u>маску слоя</u>. Чтобы правильно использовать Physics.Raycast, вам нужно создать маску слоя с помощью сдвига.
Вот как это сделать:
```csharp
int layer = LayerMask.NameToLayer("Unit");
int layerMask = 1 << layer;
Physics.Raycast(ray, out hitInfo, maxDistance, layerMask);
```
Теперь Physics.Raycast будет производить лучевую проверку только для объектов на слое "Unit".
GPT-4
##### А если нужно указать три слоя для маски слоя?
Вам просто нужно объединить их, используя оператор "ИЛИ" (|).
Вот пример с тремя слоями:
```csharp
int layer1 = LayerMask.NameToLayer("Unit");
int layer2 = LayerMask.NameToLayer("Ground");
int layer3 = LayerMask.NameToLayer("Obstacles");
int layerMask = (1 << layer1) | (1 << layer2) | (1 << layer3);
Physics.Raycast(ray, out hitInfo, maxDistance, layerMask);
```
Теперь Physics.Raycast будет производить лучевую проверку только для объектов на слоях "Unit", "Ground" и "Obstacles".
GPT-4
##### А что насчет использования LayerMask.GetMask("Unit");
Да, вы также можете использовать LayerMask.GetMask() для создания маски слоя из нескольких слоев по именам. Вот пример с тремя слоями:
```csharp
int layerMask = LayerMask.GetMask("Unit", "Ground", "Obstacles");
Physics.Raycast(ray, out hitInfo, maxDistance, layerMask);
```