Pull to refresh

Простой и быстрый алгоритм генерации ландшафта

Reading time 2 min
Views 25K
Доброго времени суток, Хабровчане! В этой статье я хочу рассказать про простой и быстрый способ генерации ландшафта. Прежде чем мы приступим к разбору самого алгоритма, хотелось бы отметить, что по отношению к генерации ландшафта мною данный алгоритм на просторах сети замечен не был, однако подобный алгоритм для генерации уровней был описан в статье, ссылка на которую будет в конце.

В какой ситуации удобен алгоритм

Недавно столкнулся с задачей: написать простую стратегию с трёхмерным ландшафтом. Так как я в данный момент обладаю маленьким опытом программирования на языке С++, мои попытки написать «diamond-square» закончились ошибками на ровном месте (ссылка на статью по «diamond-square» также будет в конце). Требовался простой в написании алгоритм, не дающий реалистичный ландшафт, так что данный метод поможет в первую очередь новичкам.

Алгоритм и результат

Прежде чем описывать сам алгоритм поделюсь его результатами:

image

Алгоритм заключается в том, что программа в случайных координатах заполняет карту прямоугольниками случайного размера. Карта имеет вид двухмерного массива, представляющего карту высот нашего ландшафта.

Для простоты создадим структуру прямоугольника:

struct tRect  
{
	int x1, y1, x2, y2;
}

Переменные x1 и y1 — левая нижняя координата прямоугольника, x2 и y2 — правая верхняя.

Пусть:

— Наша карта представлена в виде массива HM[mapsizex][mapsizey];
— mapsizey и mapsizex — переменные, определяющие размер вашей карты;
— genStep — переменная, отвечающая за количество наших прямоугольников;
— zscale — некий коэффициент растяжения карты в высоту. Можно заменить числом.
— recSizex и recSizey — пределы размеров прямоугольника.

Теперь необходимо заполнить нашу карту прямоугольниками:


for (int i=0; i<genStep; i++)
    {
        genRect.x1 = rand()%mapsizex;
        genRect.y1 = rand()%mapsizey;
        genRect.x2 = genRect.x1 + recSizex / 4 + rand()%recSizex;
        genRect.y2 = genRect.y1 + recSizey / 4 + rand()%recSizey;
        if (genRect.y2 > mapsizey) genRect.y2 = mapsizey;
        if (genRect.x2 > mapsizex) genRect.x2 = mapsizex; 
        for (int i2 = genRect.x1; i2<genRect.x2; i2++)
                for (int j2 = genRect.y1; j2<genRect.y2; j2++)
                    Map.HM[i2][j2]+= float(zscale) / float(genStep) + rand()%50 / 50.0;
    }

Рельеф со скриншота был получен значениями:

genStep = 1024
zscale = 512
mapsizex и mapsizey = 128
recSize = 10

Далее вы выводите карту на экран любым доступным вам способом. В моём случае — openGl+glfw.

Преимущества и недостатки алгоритма

Преимущества:

  • Простота и скорость в написании самого алгоритма
  • Скорость исполнения алгоритма

Недостатки:

  • Примитивность
  • При маленьком шаге заполнения карты ландшафт становится «квадратным»
  • Отсутствует возможность разбивать ландшафт на биомы по ходу генерации карты высот

Данный способ, как уже было сказано выше, подходит в первую очередь для новичков и людей, сильно ограниченных временем.

Надеюсь, данная статья была Вам полезной.

Статья про генерацию игровых уровней
Статья про «diamond-square»
Tags:
Hubs:
+13
Comments 38
Comments Comments 38

Articles