Страницы

четверг, 12 декабря 2019 г.

Процедурное создание уровней в Unity. Часть 1. Создание уровня из массива

Самый простой путь для процедурной генерации среды – это использование массива, поэтому для настройки нашей первой среды мы создадим внутренний уровень с использованием сценариев C# и массивов.

Будем действовать следующим образом:
  • Создадим массив, представляющий окружение.
  • Прочитаем массив.
  • Создадим экземпляры объектов на основе чисел из массива.
Приступим:
  • Создайте новый проект Unity.
  • Создайте новую сцену (File | New Scene) и переименуйте ее в gameLevelAuto или иначе, на ваш вкус.
  • Создайте новый куб (Game Object | 3D Object | Cube) и дайте ему новое имя ground.
  • Свойство scale для этого объекта должно быть равно (100, 1, 100), а его позиция – (0, 0, 0).
  • Вы можете создать материал и применить его к объекту ground. Для этого нужно импортировать текстуру и применить ее к объекту или создать новый цветной материал из окна проекта (Create | Material).
Затем создадим объекты, которые будут использоваться для генерации стен.
  • Создайте новый куб (Game Object | 3D Object | Cube) и дайте ему новое имя wall.
  • Задайте ему свойство scale, равное (10, 2, 10).
  • Можно создать и применить синий материал или использовать другие текстуры на ваш выбор.

Рис. 1. Создание стены

Сейчас можно создать префаб. Для этого нужно перетащить объект wall в окно проекта или создать новый префаб в окне проекта, а затем перетащить объект wall из списка объектов (Hierarchy) в этот префаб.

Рис2. Создание префаба

После этого нужно деактивировать объект wall в списке, используя Инспектор свойств (убрать галочку рядом с названием):
Рис.3. Деактивация объекта
Создадим скрипт, который будет генерировать наш лабиринт.

  • Создайте папку Scripts в каталоге Assets и затем, находясь в этой папке, выберите из контекстного меню команду «Create | New C# Script». Назовите сценарий GenerateMaze.
  • Откройте этот скрипт в выбранном вами редакторе (например,  Visual Studio Code) и добавьте следующий код в начало класса перед методом Start:

     public GameObject wall;
    private int[,] worldMap = new int[,]
   {{1,1,1,1,1,1,1,1,1,1},
    {1,2,1,0,0,0,0,0,0,1},
    {1,0,1,0,1,0,1,0,0,1},
    {1,0,1,0,0,0,0,0,0,1},
    {1,0,1,1,1,1,0,0,0,1},
    {1,0,0,0,0,0,0,0,0,1},
    {1,0,1,0,1,0,1,1,1,1},
    {1,0,0,1,0,0,0,0,0,1},
    {1,0,1,0,0,0,0,0,0,1},
    {1,1,1,1,1,1,1,1,1,1},
   };
Напомню, что быстро отформатировать код сценария в Visual Studio Code можно, нажав сочетание клавиш – Shift+Alt+F.

Рассмотрим код:

  • Мы объявляем общедоступную переменную GameObject, которая будет использоваться в качестве заполнителя в окне инспектора для создания экземпляра объекта из соответствующего префаба.
  • Затем мы объявляем многомерный массив (т. е. двумерный массив) целых чисел. Структура этого массива отражает структуру лабиринта, который мы хотели бы создать; например, верхний ряд может быть северной стеной, а нижний ряд может представлять южную стену и т. д. Таким образом, каждая единица представляет собой стену, а каждый 0 представляет собой пустое пространство.
  • Каждая строка массива определяется с помощью открывающих и закрывающих скобок со значениями внутри, разделенными запятыми.

Добавьте следующий код в метод Start:
int i, j;
for (i = 0; i < 10; i++)
{
   for (j = 0; j < 10; j++)
   {
       GameObject t;
       if (worldMap[i, j] == 1) t = (GameObject)(Instantiate(wall, new Vector3(50 - i * 10, 1.5f, 50 - j * 10), Quaternion.identity));
   }
}

  • Объявляем переменные i, j – счетчики цикла. Они представляют строки и столбцы нашего массива. Индексы в массивах начинаются с 0. Если i=1, j=3, то это фактически вторая строка и четвертый столбец массива.
  • Дальше пишем вложенный цикл – проходим наш массив построчно, затем по столбцам. Если значение элемента равно 1, то создаем экземпляр соответствующего префаба с помощью функции Instantiate. В параметрах функции указываем наш объект-заполнитель wall, затем координаты положения в формате Vector3(x, y, z), затем значение поворота (в данном случае не нужно, оставляем как есть).

Дальше осталось выполнить следующие действия:

  • Сохраните скрипт.
  • Проверьте, нет ли ошибок. Если есть, исправьте.
  • Создайте пустой объект (Create empty) в сцене и переименуйте его в generateMaze.
  • Перетащите скрипт GenerateMaze на объект generateMaze.
  • Убедитесь, что окно Инспектора активно и выбран объект generateMaze.
  • Откройте в окне проекта каталог с префабами и перетащите префаб wall на место переменной в скрипте (до перетаскивания там написано None(Game Object):

Рис. 4. Установка переменной wall в скрипте
Чтобы увидеть лабиринт сверху, измените координаты (position) камеры (Main Camera) на (0, 90, 0), а поворот (rotation) на (90, 0 , 0).
Запустите игру, нажав кнопку «Play» и проверьте лабиринт из вида игры или из вида сцены.
Рис.5. Созданный из массива лабиринт
(Если вам кажется, что все слегка скосоебилось набок, то вам не кажется, так и есть. - studhelper)

Ссылки:

Содержание
Часть 2. Создание окружения из текстового файла