
В данной статье мы разберём, как правильно генерировать случайный мир в игровом движке Unity. Способов генерации случайных уровней огромное множество. Мы лишь рассмотрим самый простой и понятный способ.
Генерацию случайного уровня мы будем рассматривать на примере 2D игры, вид сверху. Но не расстраивайтесь, данный метод так же отлично подойдёт и для 3D игры.
Описание
Для начала мы должны выбрать область, в которой будут случайным образом генерироваться объекты. Я выберу область, которая как раз покрывает нашу игровую камеру. А это, по оси X от -10 до 10. А по оси Y от -5 до 5.
На выбранном участке игровой сцены нам необходимо сгенерировать 50 объектов двух типов(блоков и кустарников), и расположить их в случайном порядке.
Итак, загрузим в окно Project спрайты(изображения) для наших объектов. Если у Вас нет под рукой никаких подходящих изображений, то можете скачать тестовые спрайты блока(Block.png) и кустарника(Brush.png) с нашего сайта.

Далее создаём игровой объект с названием Block, и подгружаем в него загруженный с нашего сайта спрайт, который имеет такое же название, Block. На его основе создаём Prefab.
Далее создаём второй игровой объект, с названием Brush, и подгружаем в него загруженный с нашего сайта спрайт, который имеет такое же название, Brush. На его основе так же создаём Prefab.

Программная часть
Создадим C# скрипт с названием Generators, в котором и будем писать весь наш код.
Для начала объявим массив object, в котором в будущем будут содержаться все наши префабы(блоки и кустарники), которые нам нужно будет генерировать на игровой сцене:
public GameObject[] object;
Теперь нам нужно выбрать случайную координату в игре, то-есть то место, где и будет создан наш игровой объект. Для этого мы случайным образом генерируем наши координаты по оси X(от -10 до 10), и по оси Y(от -5 до 5), и заносим результат значений в соответствующие переменные:
var randomX = Random.Range(-10, 10);
var randomY = Random.Range(-5, 5);
Теперь нам нужно выбрать, какой именно префаб будет создан на сцене, ведь у нас их два. Для этого создаём ещё 1 генератор случайных чисел, который и будет в случайном порядке выбирать один префаб из множества.
var rand = Random.Range(0, 2);
В данный момент мы имеем координаты, где будет создан наш префаб, а так же выбран сам префаб, который будет создан. Теперь осталось создать его, используя переменные из предыдущих примеров:
Instantiate(object[rand], new Vector2(randomX, randomY), Quaternion.identity);
Всё готово! Наша генерация работает. Осталось сделать цикл, чтобы генерировался не один объект, а множество. Для этого объединим вышеупомянутые коды в цикл for(), запустив его 50 раз.
for (var i = 0; i < 50; i++)
{
var randomX = Random.Range(-10, 10);
var randomY = Random.Range(-5, 5);
var rand = Random.Range(0, 2);
Instantiate(object[rand], new Vector2(randomX, randomY), Quaternion.identity);
}
Всё готово, результат выполнения кода видно на картинке.

Конечно же, это не совсем то что хотелось бы, ведь как мы могли заметить, один игровой объект наложен на другой, а это нам не нужно. Поэтому, напишем код, который перед созданием объекта, будет определять, создан ли на этом месте другой объект, или нет.
Для этого воспользуемся методом Physics2D.OverlapCircle(), который на определённом расстоянии ищет определённые объекты.
Объявим дополнительно 2 переменные. Первая переменная будет отвечать за радиус, от которого мы будем смотреть ближлежащие объекты. А вторая переменная будет хранить информацию не о всех объектах, а только о тех, которые имеют определённую маску:
public float groundRadius = 0.3f;
public LayerMask groundMask;
Допишем код, который будет генерировать новые игровые объекты только в тех случаях, если на этом месте нет других объектов:
var isTrue = Physics2D.OverlapCircle(new Vector2(randomX, randomY), groundRadius, groundMask);
if (!isTrue)
{
var rand = Random.Range(0, 2); Instantiate(object[rand], new Vector2(randomX, randomY), Quaternion.identity);
}
Наш код готов, результат работы видно на следующем рисунке.

Вот как выглядит ВЕСЬ код целиком:
using UnityEngine;
public class Generations : MonoBehaviour
{
public GameObject[] object;
public float groundRadius = 0.3f;
public LayerMask groundMask;
void Start()
{
for (var i = 0; i < 50; i++)
{
var randomX = Random.Range(-10, 10);
var randomY = Random.Range(-5, 5);
var isTrue = Physics2D.OverlapCircle(new Vector2(randomX, randomY), groundRadius, groundMask);
if (!isTrue)
{
var rand = Random.Range(0, 2);
Instantiate(object[rand], new Vector2(randomX, randomY), Quaternion.identity);
}
}
}
}
Единственное, что осталось сделать для корректной работы, это выполнить несколько простых действий:
- Прикрепить наш скрипт с вышеупомянутым кодом на любой игровой объект, например, на объект камеры.
- Указать всем нашим префабам, уникальный тег, например, Item.
- В окне Inspector для нашего скрипта указать в поле Ground Mask наш созданный тег Item.
- В окне Inspector для нашего скрипта указать в поле Ground Radius, расстояние, на которые должны объекты быть отделены друг от друга.
- В окне Inspector для нашего скрипта перетащить в поле все наши прифабы, которые должны будут генерироваться на игровой сцене.

На этом всё. Если Вам понравился данный гайд, буду рад Вашим лайкам.

