在网格上生成城市/城镇(仅限我的方法)

时间:2018-01-18 10:19:13

标签: algorithm procedural

问题

我正在尝试制作一个城市生成器,用于创建具有类型(住宅,工业,商业)类型的块的游戏。我所有的街道都将在90度,因为我希望它是块状的(而不是锯齿形)。

途径

我的第一个方法是选择一个起点,然后在地图上随机移动X个移动点。如果我走到了死胡同,我会追溯到一些随机数,有点像迷宫发电机,但这给我留下了许多区域,道路旁边的公路和道路没有直线行驶。我也看过使用柏林噪音,但我相信这两个会给我经常锯齿的道路。

当前解决方案

我想出了一种方法,它给了我很多我想要的东西,但我认为它比它需要的更复杂,或者至少比它更低效。目前,如果我尝试将其扩展到更大的地图,则可能需要几秒钟来处理。

JS Fiddle

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

算法

  1. 制作2D网格并填充空单元格
  2. 获取所有可能单元格的列表并将其随机播放
  3. 在洗牌列表中循环遍历每个单元格
    • 从单元格生成随机大小的矩形并为其提供唯一ID
    • 为矩形中的每个单元格指定唯一ID
    • 随机选择其类型(住宅,商业,工业)
  4. 将整个阵列按比例缩放2
  5. 遍历按比例放大的阵列,并将具有不同唯一ID的相邻图块的任何图块替换为ROAD图块。
  6. 缩放数组示例(有点像缩放图像):

    [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区域的任何图块都会生成一个地图,其中两个或多个道路图块将成为邻居。

    可视化

    enter image description here

    最终输出

    注意:这与可视化

    中的输出不同

    enter image description here

    摘要

    总结一下我的问题,是否有人就如何提高效率或更清洁提出任何建议。我认为很难为我当前的流程编写伪代码,所以我认为还有改进的余地。我还必须做更复杂的事情,比如去除1x1的细胞,因为没有房子被四面八方的街道包围。我也不希望这个城市成为一个完美的广场(所以我必须删除沿边界的随机区域并关闭他们的街道)。

1 个答案:

答案 0 :(得分:1)

规避大数组创建的一种方法是直接实现所需的布局。关键是要缩放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 Fork

https://jsfiddle.net/7srfrx55/

myTown