在网格上生成 city/town(简单来说就是我的方法)

Generating a city/town on a grid (Simply my approach)

问题

我正在尝试为游戏创建城市生成器,该游戏创建具有类型(住宅、工业、商业)的块。我所有的街道都是 90 度,因为我希望它是块状的(而不是之字形)。

方法

我的第一种方法是选择一个起点,然后在地图上随机移动 X 次。如果我遇到了死胡同,我会回溯一些随机数,有点像迷宫生成器,但这给我留下了很多区域,这些区域的道路相邻,而道路不是直线行驶。我也看过使用 perlin 噪音,但我相信这两个会给我经常曲折的道路。

当前解

我想出了一种方法,它几乎可以满足我的需求,但我认为它比它需要的更复杂,或者至少比它可能的效率低。目前,如果我尝试将其放大到更大的地图,可能需要几秒钟的时间来处理。

JS Fiddle

https://jsfiddle.net/jrj2211/0exe9jne/

算法

  1. 制作二维网格并填充空单元格
  2. 获取所有可能单元格的列表并对其进行洗牌
  3. 遍历洗牌列表中的每个单元格
    • 从单元格生成一个随机大小的矩形并为其指定唯一 ID
    • 为矩形中的每个单元格指定唯一 ID
    • 随机选择其类型(住宅、商业、工业)
  4. 将整个数组放大 2
  5. 遍历按比例放大的数组,并将具有不同唯一 ID 的相邻图块替换为 ROAD 图块的所有图块。

缩放数组示例(有点像缩放图像):

[1, 2, 2]     [1, 1, 2, 2, 2, 2]
[1, 3, 3] =>  [1, 1, 3, 3, 3 ,3]
[4, 4, 4]     [4, 4, 4, 4, 4, 4] 

我放大网格的原因是,如果我不这样做,任何以前面积为 1x1 的图块都会生成一个地图,其中两个或多个道路图块将成为邻居。

可视化

最终输出

注意:这与可视化中的输出不同

总结

总结一下我的问题,有没有人对如何提高效率或清洁度有任何建议。我认为很难为我当前的流程编写伪代码,所以我认为还有改进的余地。我还必须让它变得更加复杂,比如删除 1x1 的单元格,因为没有房子会四面八方被街道包围。我也不希望城市成为一个完美的正方形(所以我不得不删除沿边界的随机区域并关闭他们的街道)。

避免创建大型数组的一种方法是直接实现所需的布局。关键是缩放 curTile 而不是 grid,注意从 +++=2 的变化。

// Get all cells as a 1 dimensional array
function GetAllCells() {
  var cells = [];
  for (var i = 0; i < mapSize; i+=2) {
    for (var j = 0; j < mapSize; j+=2) {
      cells.push(grid[i][j]);
    }
  }
  return cells;
}

背靠背

IsInBoundsScaledIsInBounds

newGridgrid

迭代

要获得相同的方块顺序,我们必须将正方形大小加倍(参考minSizemaxSize)。

// Get a random order to loop through the cells
var checkOrder = shuffle(GetAllCells());
var minSize = 4;
var maxSize = 10;

for (var id = 1; id < checkOrder.length; id++) {
  var curTile = checkOrder[id];

  if (curTile.type == TYPES.NONE) {
    var direction = (Math.random() > .5 ? 1 : 0);
    var square_width = RandomRange(minSize, (direction ? maxSize : minSize));
    var square_height = RandomRange(minSize, (direction ? minSize : maxSize));

    var zones = [TYPES.RESIDENTIAL, TYPES.COMMERCIAL, TYPES.COMMERCIAL, TYPES.RESIDENTIAL, TYPES.INDUSTRIAL];
    var zone = zones[Math.floor(Math.random() * zones.length)];
    var color = getRandomColor();

    for (var i = 0; i < square_width; i+=2) {
      for (var j = 0; j < square_height; j+=2) {
        if (IsInBounds(curTile.i + i+1, curTile.j + j+1)) {
          grid[curTile.i + i][curTile.j + j].id = id;           // [x] O
          grid[curTile.i + i][curTile.j + j].type = zone;       //  O  O

          grid[curTile.i + i+1][curTile.j + j].id = id;         //  x [O]
          grid[curTile.i + i+1][curTile.j + j].type = zone;     //  O  O

          grid[curTile.i + i][curTile.j + j+1].id = id;         //  x  O
          grid[curTile.i + i][curTile.j + j+1].type = zone;     // [O] O

          grid[curTile.i + i+1][curTile.j + j+1].id = id;       //  x  O 
          grid[curTile.i + i+1][curTile.j + j+1].type = zone;   //  O [O]
        }
      }
    }
  }
}

JS Fiddle 分叉

https://jsfiddle.net/7srfrx55/