타일 ​​맵 생성


25

타일 ​​기반 게임을 프로그래밍하고 있으며 기본 타일 (잔디, 흙 등)이 있지만 타일이 잔디 / 흙이어야합니다.

게임 내 사진

왜 이런 일이 발생하는지 이해하지만 원하는 것은 잔디 나 흙의 임의의 연속적인 영역을 만드는 것입니다. 다음과 같이 더 의미가있는 것 :

원하는 결과


1
제안 된 답변 외에도 자신 만의 셀룰러 오토 마톤 엔진을 작성하여 이러한 맵을 생성 할 수 있습니다. 오토 마톤의 규칙을 수정하면 매우 다른 행동을 만들어 매우 다른 유형의지도로 이어질 수 있습니다. 예를 들어, Life와 유사한 2D 오토 마톤 gievn, 홍수 규칙은 "바다와 섬"(위 그림처럼)으로 이어질 수 있으며 1267/17과 같은 규칙은 아름다운 미로로 이어질 수 있습니다.
Manu343726

답변:


19

당신이 할 수있는 일은 무작위로 다음과 같이 Voronoi 맵을 생성하는 것입니다.

  1. 무작위로 따기 center points(검은 점 참조) 잔디 또는 흙인지 무작위로 결정하십시오.
  2. 그런 다음 모든 타일에서 center point먼지 나 잔디에 가장 가까운 지 확인하십시오 .
  3. 끝난!

이전에 수행 한 작업이 각 타일 (소음)에 대해 "코인 플립"인 경우 Voronoi 다이어그램을 생성하면 훨씬 더 나은 결과를 얻을 수 있습니다.

center points를 다음 islands과 같은 알고리즘 으로 나누면이를 개선 할 수 있습니다 .

  1. 작은 그룹을 선택 centers points하여로 지정합니다 leaders.
  2. 매 턴마다 무작위 인접 미정 중심점을 반복적으로 추가합니다.
  3. 끝난!

여기에 이미지 설명을 입력하십시오


1
고맙지 만 매우 어려운 해결책 인 것 같습니다.
Vilda

2
이것은 매우 어려운 해결책이 아닙니다. 먼저을 무작위로 선택하십시오 center points. 그런 다음 잔디인지 흙인지를 결정하십시오. 이제 배열을 반복하고 각 타일이 더러움 지점이나 잔디 지점에 가장 가까운 지 결정하십시오. 어쩌면 어느 부분이 도전적인지 말해 주실 수 있습니까?
wolfdawn 2016 년

거리 측정 어쨌든, 나는 당신에게 알리려고 노력할 것입니다.
Vilda

좋아, 그래서 몇 가지 포인트를 성공적으로 생성했습니다. ( dropbox.com/s/dlx9uxz8kkid3kc/random_tile_map2.png ) 그래서 생성하기위한 전체 클래스는 다음과 같습니다 : dropbox.com/s/pxhn902xqrhtli4/gen.java . 그러나 여전히 작동하지 않습니다.
Vilda

3
@ViliX 귀하의 링크가 손상되었습니다
Artur Czajka

24

하이트 맵 생성에 일반적으로 사용되는 펄린 노이즈를 사용할 수 있습니다. 게임에서 펄린 노이즈

그런 다음지도의 한 영역에서 잔디 / 흙이 발생할 가능성이 얼마나 높은지 조언자로 높이를 사용할 수 있습니다.

예 (0-256의 펄린 노이즈 값) : 값이 200을 초과하면 잔디가 놓일 확률이 80 % (흙 20 %)입니다. 값이 100과 200 사이이면 잔디가 놓일 확률은 50 %입니다 (흙도 50 %). 값이 100 미만인 경우 잔디를 놓을 확률은 20 % (흙 80 %)입니다.


자, float (0-1의 확률)의 배열 [] []이 있고 그것을 확률로 타일을 생성하는데 사용할 수 있다고 가정 해 봅시다. 그러나이 확률 배열을 어떻게 채우나요? 배열은 400x200입니다. 확률 값으로 채우는 방법은 무엇입니까?
Vilda

그는 동전 던지기와 같은 백색 소음 대신 펄린 소음으로 채울 것을 제안하고 있습니다.
wolfdawn

예,하지만 어떻게 달성 할 수 있습니까?
Vilda

내가 게시 한 링크로이 질문을 해결할 수 있습니다. 먼저 노이즈를 생성 한 다음이 노이즈를 평활화합니다. 결과적으로 2 차원 배열을 통해 차세대 타일 맵 생성에 사용할 수 있습니다. 링크
Klitz

정말 좋은 답변이지만 제시 한 것과 비슷한 결과를 거의 얻지 못합니다.
wolfdawn 2016 년

8

여기에 이미지 설명을 입력하십시오

http://gamedevelopment.tutsplus.com/tutorials/generate-random-cave-levels-using-cellular-automata--gamedev-9664

여기에 셀룰러 오토마타 방법의 내 버전은 그리드를 무작위로 채워서 시작 하고이 컬 컬러 오토마타 규칙을 몇 번 실행합니다.

  • 살아있는 세포가 살아있는 이웃이 두 개 미만이면, 죽습니다.
  • 살아있는 세포에 2 개 또는 3 개의 살아있는 이웃이 있다면, 그것은 살아있는 상태를 유지합니다.
  • 살아있는 세포가 세 개 이상의 살아있는 이웃을 가지고 있다면, 그것은 죽습니다.
  • 죽은 세포에 정확히 3 개의 살아있는 이웃이 있다면, 그것은 살아있게됩니다.

그리고 동굴처럼 보이게됩니다

이 코드로 인덱스를 x & y 위치로 변환하고 다시 변환 할 수 있습니다.

public int TileIndex(int x, int y)
{
    return y * Generator.Instance.Width + x;
}
public Vector2 TilePosition(int index)
{
    float y = index / Generator.Instance.Width;
    float x = index - Generator.Instance.Width * y;
    return new Vector2(x, y);
}

동굴, 나무, 꽃, 잔디, 안개, 물 등 여러 가지 일 에이 목록을 사용하기 때문에 부울 목록을 반환합니다. 여러 가지 방법으로 여러 목록을 결합 할 수도 있습니다. 여기서 먼저 작은 동굴을 모두 제거한 다음 두 개의 임의 목록을 결합하십시오.

여기에 이미지 설명을 입력하십시오

private int GetAdjacentCount(List<bool> list, Vector2 p)
{
    int count = 0;
    for (int y = -1; y <= 1; y++)
    {
        for (int x = -1; x <= 1; x++)
        {
            if (!((x == 0) && (y == 0)))
            {
                Vector2 point = new Vector2(p.x + x, p.y + y);
                if (PathFinder.Instance.InsideMap(point))
                {
                    int index = PathFinder.Instance.TileIndex(point);
                    if (list[index])
                    {
                        count++;
                    }
                }
                else
                {
                    count++;
                }
            }
        }
    }
    return count;
}
private List<bool> GetCellularList(int steps, float chance, int birth, int death)
{
    int count = _width * _height;
    List<bool> list = Enumerable.Repeat(false, count).ToList();
    for (int y = 0; y < _height; y++)
    {
        for (int x = 0; x < _width; x++)
        {
            Vector2 p = new Vector2(x, y);
            int index = PathFinder.Instance.TileIndex(p);
            list[index] = Utility.RandomPercent(chance);
        }
    }
    for (int i = 0; i < steps; i++)
    {
        var temp = Enumerable.Repeat(false, count).ToList();
        for (int y = 0; y < _height; y++)
        {
            for (int x = 0; x < _width; x++)
            {
                Vector2 p = new Vector2(x, y);
                int index = PathFinder.Instance.TileIndex(p);
                if (index == -1) Debug.Log(index);
                int adjacent = GetAdjacentCount(list, p);
                bool set = list[index];
                if (set)
                {
                    if (adjacent < death)
                        set = false;
                }
                else
                {
                    if (adjacent > birth)
                        set = true;
                }
                temp[index] = set;
            }
        }
        list = temp;
    }
    if ((steps > 0) && Utility.RandomBool())
        RemoveSmall(list);
    return list;
}

2
코드의 기능, 링크 및 코드 자체를 게시하는 대신 코드의 기능을 설명하십시오. 링크가 깨져도 여전히 사용할 수 있도록 답은 독립적이어야합니다.
펀드 모니카의 소송

6

지도에서 점을 선택하십시오. 원하는 타일 유형을 40과 같은 기본 값으로 배치하십시오. 새로 원하는 타일을 배치 한 위치를 추적하십시오. 시작 지점을 목록에 추가하십시오.

이 목록의 각 지점마다 모든 이웃을 방문하십시오. 충분한 전력이 남아있는 동안 (40에서 시작) 원하는 타일을 추가하고 방문 할 목록에 추가하십시오. 새 타일의 전력을 줄이십시오. 가장 쉬운 = 랜덤 하강. 목록에서 타일을 방문한 후 제거하십시오. 방문하지 않았지만 생성 된 타일을 방문하여 다시 시작하십시오.

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