İyi bir dünya haritası oluşturma algoritması arıyor [kapalı]


98

Medeniyet benzeri bir oyun üzerinde çalışıyorum ve Dünya benzeri dünya haritaları oluşturmak için iyi bir algoritma arıyorum. Birkaç alternatif denedim, ancak henüz gerçek bir kazanana ulaşmadım.

Seçeneklerden biri, Perlin gürültüsünü kullanarak bir yükseklik haritası oluşturmak ve dünyanın yaklaşık% 30'u kara olacak şekilde bir seviyede su eklemektir. Perlin gürültüsü (veya benzer fraktal tabanlı teknikler) arazi için sıklıkla kullanılır ve makul derecede gerçekçi olsa da, sonuçta ortaya çıkan kıtaların sayısı, boyutu ve konumu üzerinde kontrol sağlamak için pek bir şey sunmaz. oyun perspektifinden sahip.

Perlin gürültüsü

İkinci bir seçenek, rastgele yerleştirilmiş tek kiremitli bir tohumla başlamaktır (bir kiremit ızgarası üzerinde çalışıyorum), kıta için istenen boyutu belirlemek ve her dönüş, mevcut kıtaya yatay veya dikey olarak bitişik olan bir karo eklemektir. istediğiniz boyuta ulaştınız. Diğer kıtalar için tekrarlayın. Bu teknik, Civilization 4'te kullanılan algoritmanın bir parçasıdır. Sorun, ilk birkaç kıtayı yerleştirdikten sonra, diğer kıtalarla çevrili bir başlangıç ​​konumu seçmenin mümkün olmasıdır ve bu nedenle yenisine uymayacaktır. Ayrıca, kıtaları birbirine çok yakın bir şekilde ortaya çıkarma eğilimi vardır, bu da kıtalardan çok nehir gibi görünen bir şeyle sonuçlanır.

Rastgele genişleme

Sayıları ve göreli büyüklükleri üzerinde kontrolü elinde tutarken ızgara tabanlı bir haritada gerçekçi kıtalar oluşturmak için iyi bir algoritma bilen var mı?


3
90'dan fazla olumlu oy içeren doğal bir sorunun neden kapatılması gerektiğini anlamıyorum. Yeniden açılması için oylama.
John Coleman

Yanıtlar:


38

Doğadan bir ipucu alabilir ve ikinci fikrinizi değiştirebilirsiniz. Kıtalarınızı oluşturduktan sonra (hepsi aynı büyüklüktedir), onları rastgele hareket ettirin ve döndürün, çarpışmasını ve deforme etmesini sağlayın ve birbirlerinden uzaklaşın. (Not: Bu, uygulaması şimdiye kadar yapılması en kolay şey olmayabilir.)

Düzenleme: İşte bunu yapmanın başka bir yolu, bir uygulama ile tamamlandı - Oyunlar için Çokgen Harita Üretimi .


2
Bu harika bir fikir. Tektonik plakaları doğrudan taklit etmeye çalışmayı bilmiyorum, ancak her kıta kendi kara karolarına "sahip" olduğu sürece (bir harita dizisi için basitçe bir jeneratör görevi görmesinin aksine) ve esasen kendi plakası üzerinde oturduğu veya hareket ettiği sürece, uygulamak o kadar da zor olmaz. Bunu şimdi
denemem gerekecek

@ FerretallicA Teşekkürler. Bunu kendim de denemeye çok meraklıyım - biraz daha boş zamanım olduğunda ... :-)
David Johnstone

3
Her zaman kullanabileceğiniz ucuz bir numara, matematiksel bir işlevde neyin "iyi" bir haritayı tanımladığını tanımlamak ve ardından on rastgele küçük değişiklik oluşturmak ve sonra bunların en iyisini kullanmaktır. Bunu yapmaya devam edin, istediğiniz türden haritaya doğru kayacaktır.
dascandy

Her bir arazi parçasının hangi 'kıtaya' ait olduğunu belirlemek için K-ortalama kümelenmesinin bir değişikliğini kullanabilirsiniz. Ardından, plaka sınırlarını belirlemek için bir Voronoi diyagramı kullanın (ki bu, kümeleri tanımladıktan sonra kolay olacaktır) ... bölgeler, vb. Her bir arazi noktası, plaka sınırlarıyla ilişkili olarak konumuna bağlı olarak ayrı bir vektörle sonuçlanacak ve çalışılacak oldukça gerçekçi bir simülasyonla sonuçlanmalıdır.
Steve

Tek kiremitli tohum yöntemini kullanıyorum. Buna dağ sıraları gibi daha karmaşık arazilerin nasıl ekleneceğine dair herhangi bir öneriniz var mı?
A Tyshka

11

Yedeklemeni öneririm ve

  1. Kıtaları "iyi" yapan şeyin ne olduğunu düşünün.
  2. İyi bir kıtasal düzeni kötü olandan ayırt edebilecek bir algoritma yazın.
  3. İyi bir düzenin ne kadar iyi olduğunu ölçebilmek için algoritmayı geliştirin .

Bunu yerine getirdikten sonra, şu şekilde şekillendirilmesi gereken bir algoritma uygulamaya başlayabilirsiniz:

  • Boktan kıtalar oluşturun ve onları iyileştirin.

İyileştirme için, tavlama simülasyonu, genetik programlama ya da rastgele seçilen bir kenar karesini kıtanın kütle merkezinin karşısındaki kenara taşımak gibi tamamen geçici bir şey olsun, her türlü standart optimizasyon hilelerini deneyebilirsiniz . Ama anahtar, iyi kıtaları kötü kıtalardan ayıran bir program yazabilmektir . Hoşunuza giden bir şey elde edene kadar elle çizilmiş kıtalar ve test kıtalarıyla başlayın.


1
Bu bağlamda bu pek mantıklı değil. Fraktal bir üreteç için, berbat fraktaller üreten bir program yapıp, sahip olduğunuz şeyin iyi bir fraktal olup olmadığını söyleyen bir program yazmanız gerektiğini söylemek gibi bir şey olurdu. Başlangıçtan itibaren "doğru" yapmak çok daha kolay. Aksi takdirde, sorunun odağını ve kapsamını tamamen bozarsınız.
nathanchere

1
@FerretallicA Kesinlikle katılmıyorum. Grafiklerle, ekranda herhangi bir şey alarak başlamak çok faydalı olabilir . Sonra Sağ Beyniniz bazı işler yapmaya başlayabilir.
luser droog

11

Civilization 1'in otomatik ekran koruyucu tarzı bir klonu için peşinde olduğunuza benzer bir şey yazdım. Kayıt için bunu VB.net'te yazdım, ancak sorunuzda dil veya platform hakkında hiçbir şey söylemediğiniz için saklayacağım soyut.

"Harita" kıta sayısını, kıta boyutu varyansını (ör. 1.0, tüm kıtaları aynı yaklaşık kara alanına sahip tutacaktır, 0.1'e kadar kıtaların en büyük kıtanın 1 / 10'u ile var olmasına izin verecektir), maksimum kara alanı (yüzde olarak) üretilecek ve merkezi arazi önyargısı. Merkezi önyargıya göre haritanın merkezine doğru ağırlıklandırılan her kıta için haritanın etrafına rastgele dağıtılan bir "tohum" (örneğin, düşük bir önyargı Dünya'ya daha çok benzeyen dağıtılmış kıtalar üretir; burada yüksek bir merkezi önyargı daha çok bir Pangea). Daha sonra, büyümenin her yinelemesi için, "tohumlar", maksimum bir arazi alanına ulaşılana kadar bir dağıtım algoritmasına göre (daha sonra daha fazlası) arazi karoları atar.

Arazi dağıtım algoritması istediğiniz kadar hassas olabilir, ancak çeşitli genetik algoritmaları uygulayarak ve zarları yuvarlayarak daha ilginç sonuçlar buldum. Conway'in "Hayat Oyunu" ile başlamak gerçekten çok kolay. Kıtaların birbirine dönüşmesi gibi şeylerden kaçınmak için küresel olarak farkında olan BAZI mantık eklemeniz gerekir, ancak çoğu zaman işler kendi başlarına halleder. Daha fraktal tabanlı yaklaşımlarda bulduğum sorun (ki bu benim ilk eğilimimdi) sonuçların çok modelli görünmesi ya da hala yeterince dinamik hissetmeyen bir sonuç elde etmek için kırılma hissi veren geçici çözüm kuralları gerektiren çok fazla senaryoya yol açmasıydı. Kullandığınız algoritmaya bağlı olarak, bol miktarda tek kare okyanus kiremitleri ve damalı sahil şeritleri gibi şeyleri ortadan kaldırmak için sonuca "bulanıklaştırma" geçişi uygulamak isteyebilirsiniz. Diğerleri ile çevrili bir kıtanın ortaya çıkması ve büyüyecek hiçbir yeri kalmaması durumunda, tohumu haritada yeni bir noktaya taşıyın ve büyüme geçişlerine devam edin. Evet, bazen planlanandan daha fazla kıtaya sahip olacağınız anlamına gelebilir, ancak gerçekten kesinlikle istemediğiniz bir şeyse, bundan kaçınmanın başka bir yolu da büyüme algoritmalarını önyargılı yapmaktır, böylece diğerine en az yakın olacak şekilde büyümeyi tercih ederler. tohumlar. En kötüsü (bence yine de), bir tohumun büyüyecek ve yeni bir harita oluşturacak yeri kalmadığında seriyi geçersiz olarak işaretleyebilirsiniz. Sadece maksimum deneme sayısını belirlediğinizden emin olun, böylece gerçekçi olmayan bir şey belirtilirse (10x10'luk bir tahtaya 50 eşit ağırlıklı kıtayı sığdırmak gibi) sonsuza kadar geçerli bir çözüm bulmak için uğraşmaz.

Civ vb .'nin bunu nasıl yaptığına kefil olamam ve tabii iklim, kara yaşı vb. Şeyleri kapsamaz, ancak tohum büyüme algoritması ile oynayarak kıtalara, takımadalara vb. Benzeyen oldukça ilginç sonuçlar elde edebilirsiniz. 'organik' görünümlü nehirler, sıradağlar vb. üretmek için aynı yaklaşımı kullanın.


11

JavaScript'teki ilk resminize benzer bir şey oluşturdum. Süper karmaşık değil ama işe yarıyor:

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
Çok şık bir uygulama, beğendim.
nathanchere

Teşekkürler dostum Çok hafif ve güzel
Liberateur

9

Poligonal harita oluşturma makalesi, Voronoi poligonlarını belirleyen adım adım harita oluşturmayı açıklamaktadır.

Bu adam aynı zamanda tüm kaynak kodlarını da veriyor. Flash'dır (ActionScript 3 / ECMAScript) ancak başka herhangi bir nesne yönelimli dile dönüştürülebilir

Veya TerraJ gibi bazı fraktal çevre yazılımlarında uygulanan algoritmaları kullanmayı deneyin


5

Sadece kelepçeyi düşünüyorum:

Birkaç başlangıç ​​noktası seçin ve her birine rastgele çizilmiş (umulan) bir boyut atayın. İsterseniz planlanan kıtalar ve planlanan adalar için ayrı bir boyut çekilişini sürdürebilirsiniz.

Arazi unsurları üzerinde döngü yapın ve henüz planlanan boyutta olmadıkları yerlerde bir kare ekleyin. Ancak işin eğlenceli kısmı, komşu her bir öğenin tek olma şansını tartmaktır. Etken olabilecek bazı öneriler:

  1. En yakın "diğer" ülkeye olan mesafe. Dahası, daha iyi geniş okyanus alanları oluşturur. Ne kadar yakınsa o kadar iyi dar kanallar yapar. Bitlerin de birleşmesine izin verip vermeyeceğinize karar vermelisiniz.
  2. Tohumdan uzaklık. Ne kadar yakınsa o kadar iyidir, kompakt kara kütleleri anlamına gelir, ne kadar uzaksa o kadar iyi uzun gerilmiş bitler
  3. Bitişikteki mevcut kara karelerinin sayısı. Birçok bitişik meydanın lehine ağırlık vermek size düzgün bir sahil sağlar, birkaçını tercih etmek size çok sayıda giriş ve yarımada sağlar.
  4. Yakınlarda "kaynaklar" karelerinin varlığı? Kaynak karesi oluşturduğunuzda ve bunu kolaylaştırmak isteyip istemediğiniz oyun kurallarına bağlıdır.
  5. Uçların kutuplara yaklaşmasına veya birleşmesine izin verecek misiniz?
  6. ??? başka ne olduğunu bilmiyorum

Tüm kara kütleleri planlanan büyüklüğe ulaşana veya herhangi bir nedenle artık büyüyemeyene kadar devam edin.

Parametreyi bu ağırlıklandırma faktörlerine dahil etmenin, üretilen dünya türünü ayarlamanıza izin verdiğine dikkat edin, bu, bazı Civlerde hoşuma giden bir özellik.

Bu şekilde, her parçada ayrı ayrı arazi oluşturma yapmanız gerekecektir.


4

Yükseklik haritası gibi bir şey oluşturmak için bir elmas kare algoritması veya perlin gürültüsü deneyebilirsiniz. Ardından, haritada gösterilenlere aralık değerleri atayın. "Boyunuz" 0 ile 100 arasındaysa, 0 - 20 su, 20 - 30 kumsal, 30 - 80 çimen, 80 - 100 dağ yapın. Sanırım notch minicraft'ta buna benzer bir şey yaptı, ama ben bir uzman değilim, sadece sonunda onu çalıştırdıktan sonra bir elmas kare zihniyetindeyim.


3

Burada "dinamik programlama" stil yaklaşımını kullanabileceğinizi düşünüyorum.

Önce küçük sorunları çözün ve daha büyük sorunları çözmek için çözümleri akıllıca birleştirin.

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" ;)

Bazı "Grafik Yerleşim Algoritmalarına" göz atmak çok iyi olacaktır.

Bunları amacınıza uyacak şekilde değiştirebilirsiniz.


3

Tektonik plakaların cevabına benzer bir harita oluşturma fikrim vardı. Bunun gibi bir şey gitti:

  1. rnd <= 0.292 ise (dünya gezegenindeki kuru arazinin gerçek yüzdesi) her kareye bir "kara" karesi vererek ızgara karelerini tarayın.
  2. Her kara parçasını bir kareye en yakın büyük komşusuna doğru taşıyın. Komşular eşit uzaklıkta ise, daha büyük parçaya doğru gidin. Parçalar eşit boyuttaysa, rastgele birini seçin.
  3. iki kara karesi birbirine temas ederse, onları bir yığın halinde gruplayın, bundan sonra tüm kareleri tek bir kareye taşıyın.
  4. 2. adımdan itibaren tekrarlayın. Tüm parçalar bağlandığında durun.

Bu, yer çekiminin 3B uzayda nasıl çalıştığına benzer. Oldukça karmaşık. İhtiyaçlarınız için daha basit bir algoritma şu şekilde çalışacaktır:

  1. Rastgele x, y konumlarında ve birbirinden kabul edilebilir mesafelerde n başlangıç ​​kara karelerine bırakın. Bunlar kıtalarınızın tohumlarıdır. (Tohumların kendileriyle diğerleri arasında minimum mesafeye sahip olmasını sağlamak için Pisagor teoremini kullanın.)
  2. Bu yön bir okyanus karesiyse, rastgele bir yönde mevcut bir kara karesinden bir kara kare oluşturur.
  3. 2. adımı tekrarlayın. Kara kareleri toplam harita boyutunun% 30'unu doldurduğunda durun.
  4. kıtalar birbirine yeterince yakınsa, Panama tipi bir etkiyi simüle etmek için istendiği şekilde kara köprülerini bırakın.
  5. Daha doğal bir görünüm için istediğiniz kadar küçük, rastgele adalara bırakın.
  6. Eklediğiniz her ekstra "ada" karesi için, aynı algoritmayı tersten kullanarak kıtalardan iç denizleri ve göl karelerini kesin. Bu, arazi yüzdesini istenen miktarda tutacaktır.

Bunun nasıl çalıştığını bana bildirin. Ben kendim hiç denemedim.

PS. Bunun denediğinize benzer olduğunu görüyorum. Başlamadan önce tüm tohumları bir kerede oluşturması dışında, kıtalar birbirinden yeterince uzakta olacak ve harita yeterince dolduğunda duracak.


2

Aslında bunu denemedim ama David Johnstone'un tektonik plakalarla ilgili cevabından ilham aldı. Eski Civ projemde bunu kendim uygulamayı denedim ve iş çarpışmaları ele almaya geldiğinde başka bir fikrim vardı. Doğrudan kiremit üretmek yerine, her kıta düğümlerden oluşur. Her düğüme kütle dağıtın ve ardından bir 2D metatabanı yaklaşımı kullanarak bir dizi "blob" kıtası oluşturun. Tektonik ve kıtasal kaymanın, düğümleri hareket ettirerek "taklit etmek" gülünç derecede kolay olurdu. Ne kadar karmaşık gitmek istediğinize bağlı olarak, düğüm hareketini işlemek için akımlar gibi şeyler uygulayabilir ve örtüşen plaka sınırlarına karşılık gelen dağ sıraları oluşturabilirsiniz. Muhtemelen şeylerin oynanış yönüne pek bir şey katmazdı.

Daha önce onlarla çalışmadıysanız, metatabanların iyi bir açıklaması:

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


2

Geliştirme aşamasındaki bir oyun için sahip olduğum bunun gibi bir şeyi uygulamak üzereyken düşündüğüm şey şu. :

Dünya bölgelere ayrıldı. dünyanın büyüklüğüne göre kaç bölge belirleyecektir. Bu örnek için, 6 bölgeli orta büyüklükte bir dünya varsayacağız. Her ızgara bölgesi 9 ızgara bölgesine ayrılır. bu ızgara bölgelerinin her biri 9 ızgaraya bölünür. (bu karakter hareketi için değil, yalnızca harita oluşturmak içindir) Izgaralar biyomlar içindir, ızgara bölgeleri, kemerli arazi özellikleri içindir (kıta vs okyanus) ve bölgeler genel iklim içindir. Izgaralar fayanslara bölünür.

Rastgele oluşturulan bölgelere mantıksal iklim setleri atanır. Izgara bölgeleri rastgele atanır, örneğin; okyanus veya kara. Izgaralar, orman, çöl, ovalar, buzul, bataklık veya volkanik olmak üzere, ızgara bölgelerine ve iklime göre değiştiricilerle rastgele biyomlar atanır. Tüm bu temel özellikler atandıktan sonra, karo setlerini dolduran rastgele yüzde tabanlı bir işlev kullanarak bunları bir araya getirme zamanı. Örneğin; Eğer bir orman biyomunuz varsa, bir çöl biyomunun yanında, bir karonun "ormanlık" olma olasılığını azaltan ve "çürüme" olacağını artıran bir algoritmanız var. Yani, aralarında biraz yumuşak bir geçiş sağlamak için iki biyomu birleştiren bir çeşit harmanlanmış etki göreceksiniz. Bir ızgara bölgesinden diğerine geçiş, mantıksal kara kütlesi oluşumlarını güvence altına almak için muhtemelen biraz daha fazla çalışma gerektirecektir.Örneğin, yakınlığa dayalı basit bir anahtarlama yüzdesine sahip olmak yerine, bir ızgara bölgesinden biyoma diğerinden dokunan bir biyom gibi. Örneğin, biyomun ortasından biyomun kenarına kadar 50 karo vardır, yani dokunduğu kenardan bir sonraki biyomun merkezine 50 tane vardır. Bu, mantıksal olarak bir biyomdan diğerine% 100 değişiklik bırakacaktır. Karolar iki biyomun sınırına yaklaştıkça, yüzde yaklaşık% 60'a kadar daralır. Bence, biyomları sınırdan uzağa geçme olasılığını çok fazla vermek akıllıca olmaz, ancak sınırın bir şekilde karışmasını isteyeceksiniz. Izgara bölgeleri için yüzde değişimi çok daha belirgin olacaktır. Yüzde yaklaşık% 60'a düşmek yerine, yalnızca yaklaşık% 80'e düşer. Okyanusun yanında bir kara biyomunun ortasında herhangi bir mantık olmaksızın rastgele bir su karosu olmadığından emin olmak için ikincil bir kontrolün yapılması gerekecektir. Öyleyse, ya su karosunu açıklamak için bir kanal yapmak için o su karosunu okyanus kütlesine bağlayın ya da tamamen kaldırın. Su bazlı bir biyomdaki arazi, kaya çıkıntıları ve benzeri kullanılarak açıklanması daha kolaydır.

Oh, biraz aptal, üzgünüm.


selam! Bir harita oluşturmaya çalışırken biraz araştırma yapıyordum .. ve tam olarak tarif ettiğiniz şeyi uygulamak üzereydim. Sadece meraktan nasıl ortaya çıktı?
VivienLeger

1

Fraktal araziyi, "çalıştığını" bildiğiniz bir düzene göre (örneğin, 2x2 ızgara, elmas vb., Biraz titreyerek) ancak kıta merkezlerinin kenarlarına doğru inen Gauss dağılımlı sönümleme ile yerleştirirdim. Su seviyesini daha alçak bir yere koyun, böylece kenarlara yaklaşıncaya kadar çoğunlukla karadır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.