Шукаємо хороший алгоритм генерації карти світу [закрито]


97

Я працюю над грою, що нагадує цивілізацію, і шукаю хороший алгоритм для створення географічних карт світу. Я експериментував з декількома альтернативами, але ще не натрапив на справжнього переможця.

Один із варіантів - створити карту висоти за допомогою шуму Перліна та додати воду на рівні, щоб приблизно 30% світу було сушею. Хоча шум Перліна (або подібні фрактальні методи) часто використовуються для рельєфу місцевості і є досить реалістичним, він не дає великого способу контролю над кількістю, розміром і положенням континентів, що виникають, що я хотів би зробити мати з точки зору ігрового процесу.

Шум Перліна

Другий варіант - почати з довільно розміщеного однонасіннєвого насіння (я працюю над сіткою плиток), визначити потрібний розмір для континенту і кожен виток додати плитку, яка горизонтально або вертикально примикає до існуючого континенту до ви досягли бажаного розміру. Повторіть для інших континентів. Ця методика є частиною алгоритму, використовуваного в цивілізації 4. Проблема полягає в тому, що після розміщення перших кількох континентів можна вибрати початкове місце, яке оточене іншими континентами, і таким чином не підійде до нового. Крім того, він має тенденцію нерестувати континенти занадто близько один до одного, внаслідок чого щось більше нагадує річку, ніж континенти.

Випадкове розширення

Хтось знає хороший алгоритм для генерування реалістичних континентів на основі сітки на карті, зберігаючи контроль над їх кількістю та відносними розмірами?


2
Я не розумію, чому слід закрити природне запитання з оновленнями 90+. Голосування за повторне відкриття.
Джон Коулман

Відповіді:


38

Ви можете взяти підказку від природи та змінити свою другу ідею. Коли ви генеруєте континенти (які мають приблизно однаковий розмір), змусьте їх довільно рухатись, обертатись та стикатися та деформуватися один до одного та відходити один від одного. (Примітка. Це може бути не найпростішою річчю, яку можна було реалізувати.)

Редагувати: Ось ще один спосіб зробити це разом з реалізацією - Полігональне генерування карт для ігор .


2
Це чудова ідея. Я не знаю про спроби емуляції тектонічних плит прямо, але поки кожен континент "володіє" власною сухопутною плиткою (на відміну від того, щоб просто діяти як генератор для масиву карт) і по суті сидить на або діє як своя власна плита, це було б не так складно. Мені зараз доведеться спробувати це :)
nathanchere

@FerretallicA Дякую Мені дуже сподобається зайнятися цим - коли у мене є ще вільний час ... :-)
Девід Джонстон

3
Один дешевий трюк, який ви завжди можете використовувати, - це визначити в математичній функції те, що визначає «хорошу» карту, а потім створити десять випадкових незначних змін, а потім використовувати найкращі з них. Продовжуйте це робити, і воно рухатиметься до потрібної карти.
дасканді

Ви можете використовувати модифікацію кластеризації K-засобів, щоб визначити, яким континентом належить кожен окремий ділянку землі. Потім використовуйте діаграму Вороного (яка повинна бути простою, коли ви визначите кластери), щоб визначити межі пластини ... для кожного сегмента лінії у Вороному ви визначали б випадковий вектор руху і повинні бути здатні визначати зони землетрусів проти вулканічних зон тощо. Кожна точка суші потім закінчувалась би окремим вектором, виходячи з його розташування по відношенню до меж пластини, і повинна закінчитися досить реалістичним моделюванням.
Стів

Я використовую метод одноразового насіння. Будь-які пропозиції щодо того, як додати до цього більш складну місцевість, таку як гірські хребти?
Тишка

11

Я б запропонував вам створити резервну копію та

  1. Подумайте, що робить «хорошими» континенти.
  2. Напишіть алгоритм, який може відрізнити хороший континентальний макет від поганого.
  3. Уточніть алгоритм, щоб ви могли кількісно визначити, наскільки хорошим є хороший макет.

Після того, як ви це встановите, ви можете почати реалізовувати алгоритм, який повинен мати такий вигляд:

  • Створіть безглузді континенти, а потім вдосконалюйте їх.

Для вдосконалення ви можете спробувати всілякі стандартні прийоми оптимізації, будь то імітаційний відпал, генетичне програмування чи щось абсолютно спеціальне , як, наприклад, переміщення випадково вибраного квадратного квадрата від того місця, де він знаходиться на континенті до краю, навпроти центру маси континенту. Але головне - вміти писати програму, яка може розповісти про добрі континенти від поганих. Почніть з мальованих континентів, а також з тестовими континентами, поки не отримаєте щось, що вам подобається.


1
Це мало сенсу в цьому контексті. Було б як сказати, що для фрактального генератора вам слід зробити програму, яка генерує хитрі фрактали, а потім спробувати написати програму, яка підкаже вам, чи є у вас хороший фрактал чи ні. Набагато простіше просто отримати це "правильно" з самого початку. В іншому випадку ви повністю перекосите фокус і сферу проблеми.
nathanchere

1
@FerretallicA категорично не згоден. З графікою може бути дуже корисно почати з того , що з’явиться щось, що завгодно на екрані. Тоді ваш правий мозок може почати виконувати якусь роботу.
luser droog

11

Я написав щось подібне до того, що ви шукаєте, для автоматизованого клону в стилі заставки Civilization 1. Для запису я написав це на VB.net, але оскільки ви нічого не згадуєте про мову чи платформу у своєму питанні, я буду зберігати це абстрактно.

"Карта" вказує кількість континентів, відхилення розмірів континенту (наприклад, 1,0 підтримувало б усі континенти з однаковою приблизною площею суші, до 0,1 дозволяло б континентам існувати з 1/10 масою найбільшого континенту), максимальною площею суші (у відсотках) для генерування та центральний упереджений характер земель. "Насіння" розподіляється випадковим чином навколо карти для кожного континенту, зважене до центру карти відповідно до центрального зміщення (наприклад, низький зсув створює розподілені континенти, схожіші на Землю, де, як високий центральний ухил, буде схожий більше на Пангея). Тоді для кожної ітерації росту «насіння» призначають плитки землі згідно алгоритму розподілу (докладніше про це пізніше) до досягнення максимальної площі землі.

Алгоритм розподілу землі може бути настільки точним, як ви хочете, але я знайшов більш цікаві результати, застосовуючи різні генетичні алгоритми та перекочуючи кістки. «Гра життя» Конуея - це справді легко. Вам потрібно буде додати ДЕЯКУ глобально усвідомлену логіку, щоб уникнути речей, як континенти, що переростають один у одного, але здебільшого речі піклуються про себе. Проблемою, яку я виявив із використанням більш фрактальних підходів (що було моїм першим схильністю), було те, що результати виглядали занадто зразковими, або призвели до занадто багатьох сценаріїв, що вимагають правил обхідного способу, щоб отримати результат, який все ще не відчував себе достатньо динамічним. Залежно від алгоритму, який ви використовуєте, ви можете застосувати «розмиття» проходу над результатом, щоб усунути такі речі, як рясна плитка одного океану та квадратних узбережжя. У випадку, якщо щось подібне до континенту, що породився в оточенні кількох інших, і де вже не було де рости, перенесіть насіння в нову точку на карті та продовжте зростання. Так, це може означати, що іноді у вас трапляється більше континентів, ніж планувалося, але якщо це дійсно щось, чого ви твердо не хочете, то іншим способом уникнути цього є упередження алгоритмів зростання, щоб вони сприяли зростанню в напрямку з найменшою близькістю до інших насіння. У гіршому випадку (на мою думку, у будь-якому випадку), ви можете позначити серію як недійсну, коли насінню нікуди не залишилось рости та генерувати нову карту. Просто переконайтеся, що ви встановили максимальну кількість спроб, тому якщо вказується щось нереально (наприклад, розміщення 50 рівних зважених континентів на дошці 10х10), це не витрачає вічно на пошук дійсного рішення.

Я не можу поручитися, як це роблять Civ і т. Д., І, звичайно, не охоплює таких речей, як клімат, вік землі тощо, але граючи з алгоритмом росту насіння, ви можете отримати досить цікаві результати, що нагадують континенти, архіпелаги тощо. Ви можете використовуйте той самий підхід для створення "органічних" річок, гірських хребтів тощо.


11

Я створив щось подібне до вашого першого зображення в JavaScript. Це не надто витончено, але працює:

http://jsfiddle.net/AyexeM/zMZ9y/

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<style type="text/css">
    #stage{
        font-family: Courier New, monospace;
    }
    span{
        display: none;
    }
    .tile{
        float:left;
        height:10px;
        width:10px;
    }
    .water{
        background-color: #55F;
    }
    .earth{
        background-color: #273;
    }
</style>
</head>

<body>


<div id="stage">

</div>

<script type="text/javascript">

var tileArray = new Array();
var probabilityModifier = 0;
var mapWidth=135;
var mapheight=65;
var tileSize=10;

var landMassAmount=2; // scale of 1 to 5
var landMassSize=3; // scale of 1 to 5


$('#stage').css('width',(mapWidth*tileSize)+'px');


for (var i = 0; i < mapWidth*mapheight; i++) {

    var probability = 0;
    var probabilityModifier = 0;

    if (i<(mapWidth*2)||i%mapWidth<2||i%mapWidth>(mapWidth-3)||i>(mapWidth*mapheight)-((mapWidth*2)+1)){

        // make the edges of the map water
        probability=0;
    }
    else {

        probability = 15 + landMassAmount;

        if (i>(mapWidth*2)+2){

            // Conform the tile upwards and to the left to its surroundings 
            var conformity =
                (tileArray[i-mapWidth-1]==(tileArray[i-(mapWidth*2)-1]))+
                (tileArray[i-mapWidth-1]==(tileArray[i-mapWidth]))+
                (tileArray[i-mapWidth-1]==(tileArray[i-1]))+
                (tileArray[i-mapWidth-1]==(tileArray[i-mapWidth-2]));

            if (conformity<2)
            {
                tileArray[i-mapWidth-1]=!tileArray[i-mapWidth-1];
            }
        }

        // get the probability of what type of tile this would be based on its surroundings 
        probabilityModifier = (tileArray[i-1]+tileArray[i-mapWidth]+tileArray[i-mapWidth+1])*(19+(landMassSize*1.4));
    }

    rndm=(Math.random()*101);
    tileArray[i]=(rndm<(probability+probabilityModifier));

}

for (var i = 0; i < tileArray.length; i++) {
    if (tileArray[i]){
        $('#stage').append('<div class="tile earth '+i+'"> </div>');
    }
    else{
        $('#stage').append('<div class="tile water '+i+'"> </div>');
    }
}

</script>

</body>
</html>

3
Дуже елегантна реалізація, мені подобається.
nathanchere

Спасибі хлопець !! Це дуже легко і приємно
Liberateur

9

У статті про створення полігональних карт описується поетапна генерація карти, що розкриває полігони Вороного.

Цей хлопець також дає всі вихідні коди. Це Flash (ActionScript 3 / ECMAScript), але переміщується на будь-яку іншу об'єктно-орієнтовану мову

Або спробуйте використовувати алгоритми, реалізовані в деяких програмних забезпеченнях фрактального оточення, таких як TerraJ


5

Тут просто придумуючи манжету:

Виберіть декілька вихідних точок та призначте кожному випадково намальований (сподіваючись) розмір. Якщо ви хочете, ви можете зберегти окремий розмір для планових континентів та запланованих островів.

Проведіть петлю над елементами землі, а там, де їх ще немає на запланованому розмірі, додайте один квадрат. Але найцікавіша частина - це зважування шансів на те, що кожен сусідній елемент буде одним. Деякі запропоновані речі, які можуть вплинути на:

  1. Відстань до найближчої "іншої" землі. Далі краще генерує широкі океанічні простори. Ближче краще робити вузькі канали. Ви повинні вирішити, чи збираєтесь ви також дозволити злиття бітів.
  2. Відстань від насіння. Ближче краще - це компактні наземні маси, чим краще, це означає довгі нанизані шматочки
  3. Кількість існуючих земельних площ, що примикають. Зважування на користь багатьох сусідніх квадратів дає вам рівне узбережжя, а перевагу небагатьох дає багато входів і півострів.
  4. Наявність «ресурсних» площ поблизу? Залежить від правил гри, коли ви генеруєте квадрат ресурсів, і якщо ви хочете зробити це просто.
  5. Чи дозволите ви бітам наближатися або з'єднуватися зі стовпами?
  6. ??? не знаю, що ще

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

Зауважте, що приведення параметрів до цих коефіцієнтів ваги дозволяє налаштувати тип сформованого світу, що є особливістю, яка мені сподобалась у деяких Civs.

Таким чином вам потрібно буде робити генерацію рельєфу на кожному шматочку окремо.


4

Ви можете спробувати алмазний квадрат алгоритму або шум перлин, щоб створити щось на зразок карти висоти. Потім призначте значення діапазонів тому, що відображається на карті. Якщо ваш «зріст» сягає від 0 до 100, то зробіть 0 - 20 води, 20 - 30 пляжів, 30 - 80 трави, 80 - 100 гір. Я думаю, що на вишу зробив щось подібне до цього в міні-кораблі, але я не фахівець, я просто в діамантовому складі розуму, нарешті, після того, як нарешті налагодив його.


3

Я думаю, ви можете використовувати тут підхід до стилю "динамічного програмування".

Спочатку вирішіть невеликі проблеми та комбінуйте рішення розумно, щоб вирішити більшу проблему.

A1= [elliptical rectangular random ... ]// list of continents with area A1 approx. 
A2= [elliptical rectangular random ... ]// list of continents with area A2 approx.
A3= [elliptical rectangular random ... ]// list of continents with area A3 approx.
...
An= [elliptical rectangular random ... ]// list of continents with area An approx.

// note that elliptical is approximately elliptical in shape and same for the other shapes.

Choose one/more randomly from each of the lists (An).

Now you have control over number and area of continents.

You can use genetic algorithm for positioning them 
as you see "fit" ;)

Буде дуже добре поглянути на деякі "Алгоритми компонування графіків"

Ви можете змінити їх відповідно до своїх цілей.


3

У мене була ідея створення карти, подібної до відповіді тектонічних плит. Це пройшло приблизно так:

  1. прокрутіть квадрати сітки, даючи кожному квадрату "земельний" квадрат, якщо rnd <= 0,292 (фактичний відсоток сухої землі на планеті Земля).
  2. Перемістіть кожен куточок землі по одному квадрату до найближчого більшого сусіда. Якщо сусідки рівновіддалені, йдіть до більшого шматка. Якщо шматки однакового розміру, виберіть один випадковим чином.
  3. якщо два земельні квадрати торкаються, згрупуйте їх у шматок, відтепер переміщаючи всі квадрати як один.
  4. повторіть з кроку 2. Зупиніться, коли всі шматки підключені.

Це схоже на те, як гравітація працює в тривимірному просторі. Це досить складно. Більш простий алгоритм для ваших потреб працював би наступним чином:

  1. Опустіть n стартових квадратів землі у випадкових положеннях x, y та допустимій відстані один від одного. Це насіння для ваших континентів. (Використовуйте теорему Піфагора, щоб забезпечити мінімальну відстань насіння між собою та всіма іншими).
  2. породжує земельну площу від існуючої земельної площі у випадковому напрямку, якщо цей напрямок є площею океану.
  3. повторіть крок 2. Зупиніться, коли земельні площі заповнять 30% від загального розміру карти.
  4. якщо континенти знаходяться досить близько один до одного, киньте наземні мости за бажанням, щоб імітувати ефект типу Панама.
  5. Зайдіть на менші випадкові острови за бажанням для більш природного вигляду.
  6. для кожної додаткової «острівної» площі, яку ви додаєте, виріжте внутрішні моря та озерні площі з континентів, використовуючи той самий алгоритм у зворотному напрямку. Це дозволить підтримувати відсоток землі в потрібній кількості.

Дайте мені знати, як це виходить. Я ніколи цього не пробував сам.

PS. Я бачу, це схоже на те, що ви намагалися. За винятком того, що він збирає всі насіння одразу перед початком, тому континенти будуть досить далеко один від одного і зупиняться, коли карта буде достатньо заповнена.


2

Я насправді цього не пробував, але це надихнуло відповідь Девіда Джонстона щодо тектонічних плит. Я спробував реалізувати це сам у своєму старому проекті Civ, і коли справа дійшла до вирішення колізій, у мене була інша ідея. Замість генерації плиток безпосередньо, кожен континент складається з вузлів. Розподіліть масу на кожен вузол, а потім генеруйте низку континентів, що «заграють», використовуючи двовимірний метаболічний підхід. Тектоніку та континентальний дрейф було б смішно легко «підробити», просто перемістивши вузли навколо. Залежно від того, наскільки складно ви хочете піти, ви навіть можете застосувати такі речі, як струми, щоб керувати рухом вузла та генерувати гірські масиви, які відповідають меж плит, що перекриваються. Напевно, це не додало би так багато ігрової сторони речей,

Хороше пояснення метаболів, якщо ви раніше не працювали з ними:

http://www.gamedev.net/page/resources/_//feature/fprogramming/exploring-metaballs-and-isosurfaces-in-2d-r2556


2

Ось що я думаю, оскільки я збираюсь реалізувати щось подібне, що у мене є для гри в розробці. :

Світ розділився на регіони. залежно від розміру світу, він визначить, скільки регіонів. Для цього прикладу ми припустимо світ середнього розміру з 6 регіонами. Кожна сітка розбивається на 9 сіток. ці зони сітки розбиваються на 9 сіток кожна. (це не для руху символів, а лише для створення карти) Сітки - це біоми, зони сітки - для надмірних особливостей суші, (континент проти океану), а регіони - для загального клімату. Сітки розпадаються на плитки.

Випадково сформовані, регіони отримують призначені логічні кліматичні набори. Зони сітки отримують, наприклад, випадковим чином; океан або суша. Сітки отримують присвоєні біоми випадковим чином з модифікаторами на основі їх сітчастих зон та клімату, серед яких ліси, пустелі, рівнини, льодовики, болота чи вулкани. Після того, як всі ці основи будуть призначені, настав час їх поєднати, використовуючи функцію, засновану на випадкових відсотках, що заповнюється наборами плиток. Наприклад; якщо у вас є лісовий біом, поруч із пустельним біомом, у вас є алгоритм, який зменшує ймовірний витяг, що плитка буде "лісовим", і збільшує, що він буде "пустельним". Отже, приблизно на половині шляху між ними, ви побачите своєрідний змішаний ефект, що поєднує два біоми, щоб усунути дещо плавний перехід між ними. Перехід від однієї зони сітки до іншої, ймовірно, потребує трохи більше роботи для страхування логічних утворень наземної маси. Як, наприклад, біома з однієї зони сітки, яка торкається біома з іншої, замість того, щоб мати простий відсоток перемикання на основі близькості. Наприклад, є 50 плиток від центру біома до краю біома, тобто 50 від краю, який він торкається до центру наступного біома. Це логічно призведе до 100% зміни від одного біому до іншого. Оскільки плитка наближається до кордону двох біомів, відсоток звужується приблизно до 60%. Думаю, було б нерозумно давати занадто велику ймовірність перетину біомів далеко від кордону, але ви хочете, щоб кордон був трохи змішаний. Для зон сітки відсоткова зміна буде набагато виразнішою. Замість того, щоб% знизилися до приблизно 60%, воно знизиться лише до приблизно 80%. І тоді слід було б провести вторинну перевірку, щоб переконатися, що посеред суходолу біома поруч із океаном не існує випадкової водяної плитки без певної логіки. Отже, або підключіть цю водяну плитку до океанічної маси, щоб зробити канал для пояснення водяної плитки, або видаліть її зовсім. Землю у біомі на водній основі легше пояснити, використовуючи відслонення гірських порід тощо.

О, якось німий, вибач.


ей там! Я робив деякі дослідження, як я намагався створити карту для .., і я збирався реалізувати саме те, що ви описали. Тільки з цікавості, як це вийшло?
VivienLeger

1

Я розмістив би фрактальну місцевість за певним макетом, який, як ви знаєте, «працює» (наприклад, сітка 2х2, алмаз тощо, з деяким тремтінням), але з гауссовим розподілом, що затухає, досягає вершин до країв континентальних центрів. Розмістіть рівень води нижче, так що це в основному земля, поки ви не наблизитесь до країв.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.