좋은 세계지도 생성 알고리즘을 찾고 있습니다.


97

저는 문명과 같은 게임을 작업 중이며 지구와 같은 세계지도를 생성하기위한 좋은 알고리즘을 찾고 있습니다. 몇 가지 대안을 실험 해 보았지만 아직 실제 승자를 찾지 못했습니다.

한 가지 옵션은 Perlin 노이즈를 사용하여 하이트 맵을 생성 하고 세계의 약 30 %가 육지가되도록 레벨에 물을 추가하는 것입니다. Perlin 노이즈 (또는 유사한 프랙탈 기반 기술)는 지형에 자주 사용되며 합리적으로 사실적이지만 결과 대륙의 수, 크기 및 위치를 제어하는 ​​방법은별로 제공하지 않습니다. 게임 플레이 관점에서 볼 수 있습니다.

펄린 노이즈

두 번째 옵션은 무작위로 배치 된 1 타일 시드 (타일 격자에서 작업 중)로 시작하고 대륙에 대해 원하는 크기를 결정한 다음 매 차례마다 기존 대륙에 수평 또는 수직으로 인접한 타일을 추가하는 것입니다. 원하는 크기에 도달했습니다. 다른 대륙에 대해서도 반복합니다. 이 기술은 문명 4에서 사용되는 알고리즘의 일부입니다. 문제는 처음 몇 개의 대륙을 배치 한 후에 다른 대륙으로 둘러싸인 시작 위치를 선택할 수 있으므로 새로운 대륙에 맞지 않는다는 것입니다. 또한 대륙이 너무 가깝게 스폰되는 경향이있어 대륙보다 강처럼 보이는 것이 생깁니다.

무작위 확장

그리드 기반지도에서 실제 대륙을 생성하는 동시에 수와 상대적인 크기를 제어 할 수있는 좋은 알고리즘을 아는 사람이 있습니까?


2
나는 왜 90 개 이상의 찬성표를 가진 자연스러운 질문을 닫아야하는지 모르겠습니다. 재 개설 투표.
John Coleman

답변:


38

자연 으로부터 신호를 받아 두 번째 아이디어를 수정할 수 있습니다. 대륙 (모두 거의 같은 크기)을 생성 한 후에는 무작위로 이동하고 회전하고 충돌하고 변형하고 서로 떨어져 표류하도록합니다. (참고 : 이것은 구현하기 가장 쉬운 방법이 아닐 수 있습니다.)

편집 : 여기에 구현을 완료하는 또 다른 방법이 있습니다.- 게임용 다각형지도 생성 .


2
이것은 좋은 생각입니다. 나는 지각판을 똑바로 모방하는 것에 대해 모르지만, 각 대륙이 자신의 땅 타일을 "소유"하고 (단순히지도 배열의 생성기 역할을하는 것과는 반대로) 본질적으로 자신의 판에 앉거나 그 역할을하는 한, 구현하기가 그렇게 어렵지 않을 것입니다. 나는 :) 지금이 시도해야 할거야
nathanchere

@FerretallicA 감사합니다. 내가 좀 더 자유 시간이있을 때 ... :-) - 나는 정말이 나 자신을 갈을 유혹하고있어
데이비드 존스톤

3
항상 사용할 수있는 저렴한 트릭 중 하나는 "좋은"맵을 정의하는 수학 함수를 정의한 다음 10 개의 임의의 사소한 변경 사항을 만든 다음 가장 좋은 점을 사용하는 것입니다. 계속 그렇게하면 원하는지도로 표류 할 것입니다.
dascandy

K- 평균 클러스터링 수정을 사용하여 각 개별 토지가 소유 한 '대륙'을 결정할 수 있습니다. 그런 다음 보로 노이 다이어그램 (클러스터를 정의하면 쉬울 것임)을 사용하여 판 경계를 결정합니다. 보로 노이의 각 선분에 대해 임의의 모션 벡터를 결정하고 지진대와 화산을 결정할 수 있어야합니다. 각 토지의 지점은 판 경계와 관련된 위치를 기반으로하는 개별 벡터로 끝나고 작업 할 수있는 상당히 현실적인 시뮬레이션으로 끝나야합니다.
Steve

1 타일 시드 방법을 사용하고 있습니다. 여기에 산맥과 같은 더 복잡한 지형을 추가하는 방법에 대한 제안이 있습니까?
A Tyshka

11

나는 당신이 백업을 제안하고

  1. 무엇이 "좋은"대륙을 만드는지 생각해보십시오.
  2. 좋은 대륙 레이아웃과 나쁜 레이아웃을 구분할 수있는 알고리즘을 작성하십시오.
  3. 좋은 레이아웃이 얼마나 좋은지 정량화 할 수 있도록 알고리즘을 수정하십시오 .

일단 그것이 제자리에 있으면 다음과 같은 모양의 알고리즘을 구현할 수 있습니다.

  • 엉뚱한 대륙을 생성하고 개선하십시오.

개선을 위해 시뮬레이션 된 어닐링, 유전자 프로그래밍, 또는 무작위로 선택한 가장자리 사각형을 대륙의 어디에서나 대륙의 질량 중심 반대편 가장자리로 이동하는 것과 같이 완전히 임시적인 모든 종류의 표준 최적화 트릭을 시도 할 수 있습니다 . 그러나 핵심은 좋은 대륙과 나쁜 대륙을 구분할 수 있는 프로그램 을 작성할 수있는 것입니다. 원하는 것을 얻을 때까지 손으로 그린 ​​대륙과 테스트 대륙으로 시작하십시오.


1
이 맥락에서는 말이되지 않습니다. 프랙탈 생성기의 경우 엉뚱한 프랙탈을 생성하는 프로그램을 만든 다음 가지고있는 것이 좋은 프랙탈인지 여부를 알려주는 프로그램을 작성해야한다고 말하는 것과 같습니다. 처음부터 '올바르게'얻는 것이 훨씬 쉽습니다. 그렇지 않으면 문제의 초점과 범위가 완전히 왜곡됩니다.
nathanchere

1
@FerretallicA 매우 동의하지 않습니다. 그래픽 을 사용하면 화면에서 무언가 를 얻는 것으로 시작하는 것이 매우 유용 할 수 있습니다 . 그러면 우뇌가 일을 시작할 수 있습니다.
luser droog 2013

11

나는 문명 1의 자동화 된 화면 보호기 스타일의 클론을 위해 당신이 추구하는 것과 비슷한 것을 썼습니다. 기록을 위해 저는 이것을 VB.net에 썼습니다. 그러나 당신은 당신의 질문에서 언어 나 플랫폼에 대해 아무것도 언급하지 않았기 때문에 나는 유지할 것입니다 추상적입니다.

"지도"는 대륙의 수, 대륙 크기 차이를 지정합니다 (예 : 1.0은 동일한 대략적인 토지 면적을 가진 모든 대륙을 유지하고 0.1까지 낮추면 가장 큰 대륙 질량의 1/10로 대륙이 존재할 수 있음), 최대 육지 면적 (백분율로) 생성하고 중앙 토지 편향. "시드"는 각 대륙에 대해지도 주위에 무작위로 분포되며, 중앙 편향에 따라지도의 중심을 향해 가중치가 부여됩니다 (예 : 낮은 편향은 지구와 더 유사한 분산 된 대륙을 생성하며, 높은 중심 편향은 Pangaea). 그런 다음 성장의 각 반복에 대해 "씨앗"은 최대 토지 면적에 도달 할 때까지 분배 알고리즘 (나중에 자세히 설명)에 따라 토지 타일을 할당합니다.

토지 분배 알고리즘은 원하는만큼 정확할 수 있지만 다양한 유전 알고리즘을 적용하고 주사위를 굴려 더 흥미로운 결과를 찾았습니다. Conway의 "Game of Life"는 시작하기 정말 쉽습니다. 대륙이 서로 성장하는 것을 피하기 위해 전 세계적으로 인식하는 논리를 추가해야하지만 대부분의 경우 자체적으로 처리됩니다. 더 많은 프랙탈 기반 접근 방식에서 발견 한 문제 (첫 번째 경향)는 결과가 너무 패턴 화되어 보이거나 여전히 충분히 역동적이지 않은 결과를 얻기 위해 해키 느낌의 해결 규칙이 필요한 너무 많은 시나리오로 이어졌다는 것입니다. 사용하는 알고리즘에 따라 결과에 "흐리게"패스를 적용하여 풍부한 단일 정사각형 바다 타일 및 체크 무늬 해안선과 같은 것들을 제거 할 수 있습니다. 여러 대륙으로 둘러싸여 있고 성장할 곳이 남지 않은 대륙과 같은 것이 생성되는 경우, 씨앗을지도의 새로운 지점으로 옮기고 성장 과정을 계속하십시오. 예, 때로는 계획된 것보다 더 많은 대륙으로 끝날 수 있지만 실제로 원하지 않는 경우이를 방지하는 또 다른 방법은 성장 알고리즘을 편향하여 다른 사람과 가장 근접한 방향으로 성장하는 것을 선호하는 것입니다. 씨앗. 최악의 경우 (어쨌든 내 의견으로는) 씨앗이 자라서 새 맵을 생성 할 곳이 없을 때 시리즈를 유효하지 않은 것으로 표시 할 수 있습니다. 최대 시도 횟수를 설정하여 비현실적인 것이 지정된 경우 (예 : 10x10 보드에 균등 가중치가 적용된 50 개 대륙을 맞추는 것과 같이) 유효한 솔루션을 찾는 데 영원히 소비하지 않도록하십시오.

문명 등이 어떻게하는지 보증 할 수없고, 물론 기후, 토지 나이 등과 같은 것들을 다루지는 않지만 종자 성장 알고리즘을 가지고 놀아 보면 대륙, 군도 등과 유사한 꽤 흥미로운 결과를 얻을 수 있습니다. 동일한 접근 방식을 사용하여 '유기농'으로 보이는 강, 산맥 등도 생성합니다.


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

다각형지도 생성 문서는 Voronoi 다각형을 제거하는 단계별지도 생성을 설명합니다.

이 사람은 또한 모든 소스 코드를 제공합니다. Flash (ActionScript 3 / ECMAScript)이지만 다른 객체 지향 언어로 변환 가능

또는 다음과 같은 프랙탈 환경 소프트웨어에서 구현 된 알고리즘을 사용해보십시오. TerraJ


5

여기 커프를 생각하면 :

몇 가지 시작점을 선택하고 각각 무작위로 그린 (원하는) 크기를 할당합니다. 원하는 경우 계획된 대륙 및 계획된 섬에 대해 별도의 크기 그리기를 유지할 수 있습니다.

토지 요소를 반복하고 아직 계획된 크기가 아닌 경우 사각형 하나를 추가합니다. 그러나 재미있는 부분은 인접한 각 요소가 하나가 될 가능성을 평가하는 것입니다. 고려할 수있는 몇 가지 제안 :

  1. 가장 가까운 "다른"땅까지의 거리. 더 나아가 넓은 해양 공간을 생성하는 것이 좋습니다. 가까울수록 채널이 좁아집니다. 비트 병합도 허용할지 결정해야합니다.
  2. 종자로부터의 거리. 가까울수록 콤팩트 한 땅덩어리를 의미하고, 멀수록 낫다는 것은 긴 비트를 의미합니다.
  3. 인접한 기존 토지 광장의 수입니다. 인접한 많은 사각형을 선호하는 가중치는 부드러운 해안을 제공하고 소수를 선호하면 많은 유입구와 반도를 제공합니다.
  4. 근처에 "자원"광장이 있습니까? 게임 규칙, 리소스 스퀘어 생성시기 및 쉽게 만들고 싶은지 여부에 따라 다릅니다.
  5. 비트가 극에 접근하거나 결합하도록 허용 하시겠습니까?
  6. ??? 또 무엇을 몰라

모든 땅 덩어리가 계획된 크기에 도달하거나 어떤 이유로 더 이상 성장할 수 없을 때까지 계속합니다.

이러한 가중치 요인에 매개 변수를 적용하면 생성 된 세계의 종류를 조정할 수 있습니다.이 기능은 일부 문명에 대해 좋아하는 기능입니다.

이렇게하면 각 비트에서 개별적으로 지형 생성을 수행해야합니다.


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 단계부터 반복합니다. 모든 청크가 연결되면 중지합니다.

이것은 3D 공간에서 중력이 작동하는 방식과 유사합니다. 꽤 복잡합니다. 필요에 따라 더 간단한 알고리즘은 다음과 같이 작동합니다.

  1. 임의의 x, y 위치와 서로 허용 가능한 거리에서 n 개의 스타터 랜드 스퀘어를 드롭합니다. 이것이 여러분 대륙의 씨앗입니다. (피타고라스 정리를 사용하여 씨앗이 자신과 다른 모든 씨앗 사이에 최소 거리를 갖도록합니다.)
  2. 해당 방향이 오션 스퀘어 인 경우 기존 랜드 스퀘어에서 임의의 방향으로 랜드 스퀘어를 생성합니다.
  3. 2 단계를 반복합니다. 토지 사각형이 전체지도 크기의 30 %를 채우면 중지합니다.
  4. 대륙이 서로 충분히 가까우면 파나마 유형 효과를 시뮬레이션하기 위해 원하는대로 육교를 떨어 뜨립니다.
  5. 보다 자연스러운 모습을 위해 원하는대로 더 작고 임의의 섬에 드롭합니다.
  6. 추가 한 각 추가 "섬"사각형에 대해 동일한 알고리즘을 사용하여 대륙에서 내륙 바다와 호수 사각형을 반대로 잘라냅니다. 이렇게하면 토지 비율이 원하는 양으로 유지됩니다.

어떻게 작동하는지 알려주세요. 나는 그것을 직접 시도한 적이 없습니다.

추신. 나는 이것이 당신이 시도한 것과 비슷하다는 것을 알았습니다. 시작하기 전에 모든 씨앗을 한꺼번에 설정하는 것을 제외하고는 대륙이 충분히 떨어져 있고지도가 충분히 채워지면 멈출 것입니다.


2

나는 실제로 이것을 시도하지는 않았지만 지각 판에 관한 David Johnstone의 대답에서 영감을 얻었습니다. 이전 Civ 프로젝트에서 직접 구현해 보았고 충돌 처리에 관해서는 또 다른 아이디어가있었습니다. 타일을 직접 생성하는 대신 각 대륙은 노드로 구성됩니다. 각 노드에 질량을 분배 한 다음 2D 메타 볼 접근 방식을 사용하여 일련의 "블럽"대륙을 생성합니다. 구조론과 대륙 이동은 단순히 노드를 이동하는 것만으로도 "가짜"가되기 쉽습니다. 얼마나 복잡한 지에 따라 전류와 같은 것을 적용하여 노드 이동을 처리하고 플레이트 경계가 겹치는 산맥을 생성 할 수도 있습니다. 아마도 게임 플레이 측면에 그다지 많이 추가하지 않을 것입니다.

메타 볼을 사용한 적이없는 경우 메타 볼에 대한 좋은 설명 :

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 %로만 떨어집니다. 그리고 나서 바다 옆에있는 육지 생물 군계 중간에 어떤 논리도없이 무작위 물 타일이 없는지 확인하기 위해 2 차 점검을 수행해야합니다. 따라서 그 물 타일을 해양 덩어리에 연결하여 물 타일을 설명하는 채널을 만들거나 모두 제거하십시오. 수중 생물 군계의 토지는 암석 노두 등을 사용하여 설명하기가 더 쉽습니다.

오, 좀 멍청 해요, 미안 해요.


안녕하세요! 나는지도를 생성하려고 노력하면서 약간의 조사를하고 있었다. 그리고 나는 당신이 묘사 한대로 정확하게 구현하려고했다. 호기심 때문에 어떻게 되었습니까?
VivienLeger 2017 년

1

나는 당신이 알고있는 일부 레이아웃 (예 : 2x2 격자, 다이아몬드 등, 약간의 지터가있는)에 따라 프랙탈 지형을 배치하지만 대륙 중심의 가장자리를 향해 아래로 피크를 감쇠하는 가우스 분포를 사용합니다. 가장자리에 가까워 질 때까지 대부분 땅이되도록 수위를 낮추십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.