用画布绘制的迷宫

问题描述 投票:0回答:2

作为一个侧面项目,我使用图形创建了一个迷宫生成器。这一代的逻辑工作正常,但我遇到了渲染它的一些问题。在我的逻辑中,每个单元被表示为4个边的阵列,其中第一个边是顶壁,第二个边是右边墙,依此类推。如果有一条边(任何不同于-1的边),那么应该有一面墙,如果有-1那边应该打开。

为了尝试遵循这个逻辑,我创建了以下Render类

export class Renderer {
  private _context: CanvasRenderingContext2D;
  private _y: number;
  private _x: number;

  constructor(canvas: HTMLCanvasElement, xSize: number, ySize: number) {
    this._context = canvas.getContext('2d') as CanvasRenderingContext2D;
    this._x = xSize;
    this._y = ySize
  }


  public render(graphAdjacencyList: Array<Vertex>): void {
    for (let i = 0; i < this._x; i++) {
      for (let j = 0; j < this._y; j++) {
        const codedIndex: number = parseInt(i.toString() + j.toString());
        this._renderCell({ x: 20 * j, y: 20 * i }, graphAdjacencyList[codedIndex].getEdges(), 20)
      }
    }
  }


  private _renderCell(coords: Record<'x' | 'y', number>, cellWalls: Array<number>, size: number) {
    cellWalls.forEach((w: number, index: number) => {
      this._context.beginPath();
      switch (index) {
        case 0:
          this._context.moveTo(coords.x, coords.y);
          (w !== -1) ? this._context.lineTo(coords.x + size, coords.y) : null;
          break;
        case 1:
          this._context.moveTo(coords.x + size, coords.y);
          (w !== -1) ? this._context.lineTo(coords.x + size, coords.y + size) : null;
          break;
        case 2:
          this._context.moveTo(coords.x + size, coords.y + size);
          (w !== -1) ? this._context.lineTo(coords.x, coords.y + size) : null;
          break;
        case 3:
          this._context.moveTo(coords.x, coords.y + size);
          (w !== -1) ? this._context.lineTo(coords.x, coords.y - size) : this._context.moveTo(coords.x, coords.y - size);
          break;
      }

      this._context.closePath();
      this._context.stroke();
    });
  }
}

乍一看似乎工作正常,除了它呈现“鬼墙”(轻灰色笔画)的事实,就像在这张图片中5X5 maze

如果我瞥一眼边缘,我可以看到,例如,单元格[3][3]应该只有顶部和左侧墙,因为它的边缘是[23, -1, -1, 32]。我确信错误在于我如何移动这一点,但我无法确定问题。

最小的例子:https://stackblitz.com/edit/js-ys9a1j

在最小的例子中,图形不是随机的,而是以一种方式设计,结果应该包含在所有块中,只有底壁和左壁([-1,-1,1,1])

javascript typescript canvas maze
2个回答
2
投票

这里有一个逻辑问题:你是独立定义每个单元格的四个边。

例如,如果我们将单元格B2设为-1,-1,-1,-1(全部打开),C2为1,1,1,1(全部关闭),则这两个单元格之间的边缘将被C2关闭声明,即使B2声明说它应该是开放的。

 _A_|_B_|_C_|_D_|
|        
1        
|    ooo|‾‾‾|
2    o o|   |                – -> closed (wall)
|    ooo|___|                o -> open (no wall)

为避免这种情况,您需要重新考虑您的逻辑,以便检查之前是否未声明所述墙,或者甚至更好,以便您只存储一次。

我可以想到的两种方式,虽然未经测试:

- 生成图表。从迷宫的入口处,您将生成一个节点,该节点将具有四个属性:N,S,W,E,如果打开则指向另一个节点,如果应该有墙,则指向null。 经过测试,我发现图形的想法实际上也需要一个查找方法,或者它只能在两个方向上进行...

  • 2个2D阵列,一个仅用于列上的墙,一个仅用于行上的墙。

const cellWidth = 20;
const maze = generateMaze(12, 12);
const ctx = canvas.getContext('2d');
ctx.translate(cellWidth + 0.5, cellWidth + 0.5);
ctx.beginPath();
drawCols(maze.cols);
drawRows(maze.rows);
ctx.stroke();

function generateMaze(width, height) {
  const rows = generateCells(width, height);
  const cols = generateCells(height, width);
  return { cols, rows};

  function generateCells(a, b) {
    return Array.from({ length: a })
      .map(_ => Array.from({ length: b })
        .map(_ => Math.random() < 0.5)
      );
  }

}

function drawCols(list) {
  list.forEach((arr, x) => {
    arr.forEach((bool, y) => {
      if (bool) {
        ctx.moveTo(x * cellWidth, y * cellWidth);
        ctx.lineTo(x * cellWidth, y * cellWidth + cellWidth);
      }
    });
  });
}

function drawRows(list) {
  list.forEach((arr, y) => {
    arr.forEach((bool, x) => {
      if (bool) {
        ctx.moveTo(x * cellWidth, y * cellWidth);
        ctx.lineTo(x * cellWidth + cellWidth, y * cellWidth);
      }
    });
  });
}
<canvas id="canvas" width="300" height="300"></canvas>

0
投票

我发现了这个问题,与朋友一起查看代码,我们注意到渲染单元格的情况3正在绘制错误的行。这就是代码修复的方式。

感谢Kaiido,我甚至用他的建议解决了浅灰色笔画的问题,将坐标偏移0.5。

  case 3:
          this._adjustedMoveTo(coords.x, coords.y + size);
          (w !== -1) ? this._adjustedLineTo(coords.x, coords.y) : null
          break;
      }
© www.soinside.com 2019 - 2024. All rights reserved.