【问题标题】:Procedural Map Generation - determine adjacent tiles程序地图生成 - 确定相邻图块
【发布时间】:2016-03-28 14:29:30
【问题描述】:

我最初使用“Tile”的二维数组来存储程序生成的地图及其各种内容。

每个图块都包含一个相邻列表,它允许每个图块知道哪些顶点最靠近它,在 8 个不同的边上接触它(直接相邻和对角相邻)。

总体思路取自 Amit 的多边形地图生成,但我试图通过使用网格设置而不是 voronois 来简化它,但是我遇到的麻烦比我最初想象的要多。我目前的困境是在废弃 2d 数组时找出邻接关系。

这就是我在更改为列表之前的做法:

private void ConstructAdjacencyList() {

    // Create Adjacency List
    for (int x = 0; x < mapWidth; x++) {
        for (int y = 0; y < mapHeight; y++) {
            // Bool to find position of point
            bool omitLeft = false;      bool omitRight = false;
            bool omitTop = false;       bool omitBottom = false;
            // Enable bools based on position, reset on each loop               
            if (x == 0)
                omitLeft = true;                
            else if (x == mapWidth - 1)
                omitRight = true;               
            if (y == 0)
                omitTop = true;             
            else if (y == mapHeight - 1)
                omitBottom = true;

            // Add entries to list based on bool settings
            if (!omitLeft) {
                // Left center
                islandMap[x,y].adjacent.Add(islandMap[x-1,y]);
                if (!omitTop)
                    islandMap[x,y].adjacent.Add(islandMap[x-1,y-1]);
                if (!omitBottom)
                    islandMap[x,y].adjacent.Add(islandMap[x-1,y+1]);
            }

            if (!omitTop) // Top Center
                islandMap[x,y].adjacent.Add(islandMap[x,y-1]);
            if (!omitBottom) // Bottom Center
                islandMap[x,y].adjacent.Add(islandMap[x,y+1]);

            if (!omitRight) {
                // Right Center
                islandMap[x,y].adjacent.Add(islandMap[x+1,y]);
                if (!omitTop)
                    islandMap[x,y].adjacent.Add(islandMap[x+1,y-1]);
                if (!omitBottom)
                    islandMap[x,y].adjacent.Add(islandMap[x+1,y+1]);
            }               
        }
    } // End Adjacency

    Debug.Log ("Adjacencies Built");
}

x、y 值现在保存在 islandMap.point(存储 x 和 y 值的向量 2d,如下所示:)

public MapController() {
    width = height = (int)Mathf.Sqrt (tileCount);

    // Lists for points
    var points = new List<Vector2>();

    // Build a random set of points.
    for (float x = 0; x < width; x++)   {
        for (float y = 0; y < height; y++)  {
            points.Add(new Vector2(x,y));
        }
    }

    map = new Map (points, width, height, lakeTreshold);
}

地图本身目前有以下内容:

public class Map {
   Func<Vector2, bool> inside; // Contains function to randomly seed area
   bool needsMoreRandomness;

   public List<Tile> islandMap; // Previously was Tile[,] islandMap
   public int mapWidth { get; private set; } // Calculated as Sqrt(totalPoints)
   public int mapHeight { get; private set; }

以及我目前坚持使用的其他方法,例如 ConstructAdjacencyList() 方法。

那么我怎样才能在不依赖数组定位的情况下继续构建周围点的邻接列表呢?我是否可以临时从数组中引用整个列表,在这个二维数组中放置对整个列表中每个图块的引用,设置邻接关系,然后删除数组而不丢失信息?我相信它只会使用引用,所以应该没问题...每个图块都包含一个索引来存储它的构建顺序,如下所示:

foreach (var point in points) {
        var p = new Tile { index = islandMap.Count, point = point };
        p.border = point.x == 0 || point.x == mapWidth || point.y == 0 || point.y == mapHeight;
        islandMap.Add (p);
        tileLookup[point] = p;
    }

对不起,如果这太长了...我刚刚意识到它非常大 -.-

【问题讨论】:

  • 有几种方法可以解决这个问题,但您的瓦片地图的大小可能会决定哪种解决方案更合适 - 您大约要处理多少瓦片?
  • 嗨皮卡莱克,感谢您的回复。我将考虑输入最多 3000 点,目前徘徊在 300 点以下。老实说,有一次计算时间并不是什么大不了的事,只要它有效。
  • 另外,我尝试做的事情如下:Tile[,] tempArray = new Tile[mapWidth, mapHeight]; int count = 0; for (int x = 0; x &lt; mapWidth; x++) { for (int y = 0; y &lt; mapHeight; y++) { tempArray[x,y] = islandMap[count]; count++; } } 试图将所有列表元素映射到二维数组,然后从那里开始计算逻辑,我还没有测试但是,无论这是否正确,因为我无法思考如何正确测试和调试此信息。
  • 您可以将邻接存储为 Tile 对象模型的一部分。比如说,为每个图块存储一个 List,其中包含对当前图块相邻的每个图块的引用(最多 8 个)。或者您可以将 2d x & y 坐标存储在您的 tile 模型中,然后从那里使用标准 2d 逻辑进行邻接。
  • @ManoDestra 这已经是它的设置方式了。我的问题与填充每个磁贴对象中存在的特定列表有关。检查我自己的答案以获得澄清。

标签: c# list procedural-generation


【解决方案1】:

假设您没有做任何事情来弄乱分数的顺序,您可以处理1D list/array as 2D list/array。我链接的示例是用 C 语言编写的,但与思想语言无关。

话虽如此,假设您只在初始化期间执行此操作一次并且鉴于点数相对较少,您可以使用循环遍历点列表并挑选出的函数来轻松强制它邻居根据需要。我的 C# 有点生疏了,但我说的是这样的:

private List<Vector2> getAdjacenctPointList(List<Vector2> pointsList, Vector2 point){
  var adjacencyList = new List<Vector2>();
  foreach (var pt in pointList){
    var offset = Math.abs(pt.x - point.x) + Math.abs(pt.y - point.y);
    if(offset > 0 && offset <= 1.0){
      adjacencyList.add(pt);
    }
  }
  return adjacencyList;
}

【讨论】:

  • 你缺少一个 } 来结束 if 子句。
  • 感谢您的回复,实际上我使用将列表视为二维数组的相同基本思想以更简单的方式解决了这个问题。但是我确实是这样写的。我也会发布我自己的答案。
【解决方案2】:

我所采用的最终答案是所涉及的工作量最少并允许我回收上面发布的原始二维数组代码是简单地构造一个临时二维数组并将所有对它的引用存储在其中 - 创建所有邻接根据需要,然后处理(简单地通过丢失范围)二维数组。

这是使用二维阵列系统的实际方法。前几条语句后跟嵌套的 for 循环就完成了:

private void ConstructAdjacencyList() {
    Tile[,] tempArray = new Tile[mapWidth, mapHeight];

    int count = 0;

    // Populate the temp 2D array with list references
    for (int x = 0; x < mapWidth; x++) {
        for (int y = 0; y < mapHeight; y++) {
            tempArray[x,y] = islandMap[count];
            count++;            
        }
    }

    // Create Adjacency List using our TempArray
    for (int x = 0; x < mapWidth; x++) {
        for (int y = 0; y < mapHeight; y++) {
            // Bool to find position of point
            bool omitLeft = false;      bool omitRight = false;
            bool omitTop = false;       bool omitBottom = false;
            // Enable bools based on position, reset on each loop               
            if (x == 0)
                omitLeft = true;                
            else if (x == mapWidth - 1) // Optimize with if else to split checks in half.
                omitRight = true;               
            if (y == 0)
                omitTop = true;             
            else if (y == mapHeight - 1)
                omitBottom = true;

            // Add entries to list based on bool settings
            if (!omitLeft) {
                // Left center
                tempArray[x,y].adjacent.Add(tempArray[x-1,y]);
                if (!omitTop)
                    tempArray[x,y].adjacent.Add(tempArray[x-1,y-1]);
                if (!omitBottom)
                    tempArray[x,y].adjacent.Add(tempArray[x-1,y+1]);
            }
            
            if (!omitTop) // Top Center
                tempArray[x,y].adjacent.Add(tempArray[x,y-1]);
            if (!omitBottom) // Bottom Center
                tempArray[x,y].adjacent.Add(tempArray[x,y+1]);
            
            if (!omitRight) {
                // Right Center
                tempArray[x,y].adjacent.Add(tempArray[x+1,y]);
                if (!omitTop)
                    tempArray[x,y].adjacent.Add(tempArray[x+1,y-1]);
                if (!omitBottom)
                    tempArray[x,y].adjacent.Add(tempArray[x+1,y+1]);
            }               
        }
    } // End Adjacency

    Debug.Log ("Adjacencies Built");
}

为确保按我的意愿进行操作,我通过设置一个随机立方体进行视觉测试,并测试了该区域周围的各个点,以确保没有错误,也没有错误。

最终结果符合预期,如下图所示:

感谢您的帮助:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-22
    相关资源
    最近更新 更多