Процедурная Генерация для начинающих ч.2 (перевод) part1

the_JaGGer:

Процедурная генерация для начинающих
Часть 2
<terminateblog.wordpress.com>/ ABHILASH2863

В этой части туториала мы научимся как генерировать местность используя простой алгоритм. Мы начнем с наброска, который получился у нас в предыдущей части. Этот урок будет предполагать ваши базовые знания о массивах и манипуляциях с ними, а так же о выводе видимой карты.
Ну ладно, теперь можно и начать.
Для начала посмотрим на алгоритм.
- Начало.
- Заполнить всю карту стенами.
- Создать 3 «Шахтера».
Шахтеры – это просто 1D-массив, с тремя элементами, которые содержат данные о его Х и Y, а так же его направлении. Побольше о них чуть позже.
- Поставить всех шахтеров в центр карты.
- Для каждого шахтера:
Повторить 1000 раз: (это число зависит от того, насколько большая будет ваша карта)
- Изменить направление шахтера в случайную сторону. Направлен он может быть на все 4 стороны – ВВЕРХ(1), ВПРАВО(2), ВНИЗ(3), ВЛЕВО(4). Число в скобках используется для обозначения направления в массиве-шахтере.
- Передвинуть шахтера на одну единицу в сторону, куда он направлен, удалить оттуда стену и заменить землей.
После этого у нас есть грубая карта.
- Подчистим карту:
Удалить все стены, у которых 0 соседей.
- Отрисуем карту.
- Конец.
Наша карта ничто иное, как 2D-массив некоторых размеров. Шахтер – это одномерный массив с 3-мя элементами.
На карте у нас есть 3 шахтера, стартующие из одной позиции, но двигающиеся в разных направлениях при каждом шаге, а также создающие блоки земли (проходимые) на каждом блоке где они проходят. То, что все они движутся в разных направлениях, дает ветвистую структуру пещеры. Если бы мы использовали только одного шахтера, то нам пришлось бы использовать больше циклов (шагов), чтобы сделать большую карту. К тому же она могла бы иметь линейную структуру.
В начале наша карта выглядит примерно так –
«М» - это шахтер, хотя на самом деле здесь их 3, просто они перекрывают друг друга в одной клетке, т.к. начинают все из одной точки. Коричневые блоки – это стены, зеленые – земля (проходимые блоки).
С каждой итерацией шахтеры движутся в разных направлениях. После первого шага карта МОЖЕТ выглядеть так –
Повторившись 1000 раз (или сколько раз вы там указали) этот алгоритм придаст карте ветвистую структуру.
Примерно так –
Размер массива 128*96, а размеры каждого блока 5*5.
Ну ладно, достаточно теории, давайте откроем Construct.
Вот здесь законченный .сар файл, как образец. Откройте его после загрузки, он нам понадобится на протяжении всего урока
mapper%28array%29.cap

Вставим два спрайта, один из них сделаем коричневым и назовем “wall” (стена), другой сделаем зеленым и назовем “ground”, оба размером 5х5. Вставим объект MouseKeyboard и 2 массива Array. Один назовем “map” (карта), другой “miner” (шахтер).
Укажем размеры для шахтера – Width(X)=3, Height(Y)=1, Depth(Z)=1.
Размеры карты зависят от вас. Если вы хотите заполнить весь слой, то найти необходимый размер массива несложно, просто нужно поделить размер слоя на размер одного блока.
В моем случае размеры получились такие –
Width(X).640/5)=128
Height(Y)=480/5)=96
Еще нам понадобится глобальная переменная, назовем ее “clean_up”.
Перейдем же к событиям. Мне неохота объяснять как вставлять события, т.к. я надеюсь, что раз вы читаете этот урок, то скорей всего знаете все это.
Для начала, создадим еще 2 шахтера при старте уровня. Позиция нам не важна.
Теперь для каждого шахтера укажем х и у как 64 и 48 соответственно. После этого наши шахтеры оказались в центре карты. Еще нам нужно сменить их направление на 1 из 4. Надеюсь что вы помните, что первый элемент массива-шахтера отвечает за х-позицию на карте, второй отвечает за у, а третий за направление.
Каждый шахтер выглядит примерно так:
Это значит что он в центре карты и имеет случайное направление.
Вот теперь важная часть –
В этом эвенте для каждого шахтера мы повторяем блок событий 1000 раз. Сначала значение третьего элемента принимает случайное целое значение между 1 и 4 (включая 1 и 4). Потом идет блок подсобытий, в котором сначала идет проверка значения третьего элемента массива-шахтера ( где хранятся сведения о его направлении), после чего идет выполнение определенного условия.
Шахтер очень просто движется – мы просто изменяем на 1 первый элемент или второй элемент массива-шахтера и он меняет свое положение.
Продолжаем. Следующая часть –
Это события подчищают карту, отличия заметны.
Вот карта без очистки –
Как можно заметить, у карты есть куски земли, которые висят в воздухе и это не хорошо.
А вот карта с очищающими эвентами –
Ну и собственно объяснение: событие проходит по каждому элементу КАРТЫ (не шахтеров) и когда находит блок стены, проверяет на наличие 8 прилегающих блоков; если оно находит стену, прилегающую к другой стене, то глобальная переменная “clean_up” увеличивается на 1. После этого проверяются все 8 прилегающих блоков. Если таких блоков 3 или меньше (“clean_up” <=3), то событие превращает этот блок из “wall” в “ground”.
Проверка на прилегающие блоки проста, просто возьмите любой элемент массива-карты и добавьте/вычтите 1 от х и у.
В этом событии мы проверяли верхний левый прилегающий блок. Чтобы проверить остальные:
ВЕРХНИЙ ЛЕВЫЙ БЛОК - (map.CurrentX-1, map.CurrentY-1)
ВЕРХНИЙ БЛОК- (map.CurrentX, map.CurrentY-1)
ВЕРХНИЙ ПРАВЫЙ БЛОК- (map.CurrentX+1, map.CurrentY-1)
ЛЕВЫЙ БЛОК- (map.CurrentX-1, map.CurrentY)
ПРАВЫЙ БЛОК- (map.CurrentX+1, map.CurrentY-1)
НИЖНИЙ ЛЕВЫЙ БЛОК- (map.CurrentX-1, map.CurrentY+1)
НИЖНИЙ БЛОК- (map.CurrentX, map.CurrentY+1)
НИЖНИЙ ПРАВЫЙ БЛОК - (map.CurrentX+1, map.CurrentY+1)
Последняя часть –
Тут просто проверяется значение clean_up. Если оно меньше либо равно трем, то текущий элемент массива-карты превращается в “ground” (проходимый блок). Затем эвент идет проверять следующий блок, после чего повторяются события выше, ну и так далее.
Уже осталась совсем легкая часть –
Если вы прошли предыдущую часть урока, тогда вам должно быть знакомо это событие, отрисовывающее карту. Правда в этот раз она немного отличается. Вернемся в редактор слоя и изменим hotspot`ы стены и земли и поставим их сверху слева (numpad 7). В прошлом туториале hotspot`ы были по центру. Еще одно отличие заключается в том, что если вы внимательно приглядитесь, то обнаружите, что мы высчитываем позицию стен/земли умножая высоту и ширину на current.X или current.Y МИНУС 1.
Это делается потому что массивы в Констракте начинаются с 1, а не с 0. Иначе позиция карты начиналась не с нужного (0,0), а с (5,5).
Ну и самая простая последняя часть –
Нажимая на кнопку мыши, мы перезапускаем уровень.
Я думаю что этого достаточно для одного урока. Обычно я не пишу по 4 часа подряд