生成图块地图


25

我正在编写基于图块的游戏,并且有一些基本的图块(草,土等),但是我不知道如何生成良好的随机图,因为当我进行一些真正的随机选择时,如果图块应该是草/污垢,我得到这个:

游戏中图片

我知道为什么会这样,但是我想要的是创建一些随机的连续区域的草或泥土。这样更有意义的事情是这样的:

所需结果


1
除了建议的答案外,您还可以编写自己的蜂窝自动机引擎来生成此类地图。修改自动机的规则,您可能会产生非常不同的行为,从而导致非常不同的地图类型。例如,使用类似于生命的二维自动机,洪水规则可能会导致“海洋和小岛”(就像上面的图片一样),而1267/17这样的规则可能会导致美丽的迷宫。
Manu343726

Answers:


19

您可以做的是随机生成Voronoi地图,如下所示:

  1. 随机挑选center points(请参见黑点),并随机确定它们是草还是灰尘。
  2. 然后检查所有瓷砖,看是否最接近center point灰尘或草皮。
  3. 做完了!

如果您之前所做的是为每个图块(噪声)“翻转硬币”,则生成Voronoi图将提供更好的结果。

您可以通过将划分center pointsislands以下算法来对此进行改进:

  1. 从中选出一小部分centers points并指定为leaders
  2. 每回合迭代添加一个随机的,未确定的中心点。
  3. 做完了!

在此处输入图片说明


1
谢谢,但这似乎是一个非常困难的解决方案。
Vilda 2014年

2
这不是一个非常困难的解决方案。首先随机选择center points。然后确定它们是草还是泥土。现在循环遍历数组,并确定每个贴砖是否最靠近污点或草点。也许告诉我哪一部分具有挑战性?
wolfdawn

测量距离。无论如何,我会尽力让您知道。
Vilda 2014年

好的,我已经成功地产生了一些观点。(dropbox.com/s/dlx9uxz8kkid3kc/random_tile_map2.png),因此,整个生成类如下:dropbox.com/s/pxhn902xqrhtli4/gen.java。但这仍然行不通。
Vilda 2014年

3
@ViliX,您的链接已断开
Artur Czajka 2014年

24

您可以使用perlin噪声,这通常用于高度图生成。 游戏中的Perlin噪音

然后,您可以将高度用作顾问,以了解地图的一个区域中发生草皮/污垢的几率。

示例(Perlin噪声值介于0-256之间):如果该值超过200,则放置草的机会为80%(污垢20%)。如果该值在100到200之间,则放草的几率是50%(污垢也为50%)。如果该值小于100,则放置草的机会为20%(污垢80%)。


好的,假设我有一个float [[[]]的数组(概率为0-1),并且可以使用它以概率生成图块。但是,如何填充此概率数组?数组(假设)为400x200,如何用概率值填充数组?
Vilda 2014年

他建议用Perlin噪声(而不是硬币翻转之类的白噪声)填充它。
wolfdawn

是的,但是我该如何实现呢?
Vilda 2014年

我发布的链接可以清除此问题。首先生成一个噪声,然后平滑该噪声,结果将是一个二维数组,可用于进一步生成图块贴图。链接
Klitz 2014年

这是一个很好的答案,但很少会得到与您介绍的结果相似的结果。
wolfdawn

8

在此处输入图片说明

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

这是我的细胞自动机方法的版本,首先用随机填充网格,然后在其上运行这些Cullular自动机规则几次

  • 如果一个活细胞的邻居少于两个,它就会死亡。
  • 如果一个活细胞有两个或三个活着的邻居,它就可以存活。
  • 如果一个生物细胞有三个以上的生物邻居,它就会死亡。
  • 如果一个死细胞正好有三个活着的邻居,它就会活着。

最终看起来像一个山洞

可以将索引转换为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开始)时,添加所需的图块并将其添加到要访问的列表中。根据您的意愿,给新瓷砖提供更少的功率。最简单=随机降低。从列表中访问磁贴后,将其删除。通过访问所有未访问但已创建的图块重新开始。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.