Простий і швидкий алгоритм генерації ландшафту

Доброго часу доби, Хабровчане! У цій статті я хочу розповісти про простий і швидкий спосіб генерації ландшафту. Перш ніж ми приступимо до розбору самого алгоритму, хотілося б зазначити, що по відношенню до генерації ландшафту мною даний алгоритм на просторах мережі помічений не був, однак подібний алгоритм для генерації рівнів був описаний в статті, посилання на яку буде в кінці.

В якій ситуації зручний алгоритм

Нещодавно зіткнувся із завданням: написати просту стратегію з тривимірним ландшафтом. Так як я в даний момент володію маленьким досвідом програмування на мові С++, мої спроби написати «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 j 2 = 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»
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.