作为一个侧面项目,我使用图形创建了一个迷宫生成器。这一代的逻辑工作正常,但我遇到了渲染它的一些问题。在我的逻辑中,每个单元被表示为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();
});
}
}
乍一看似乎工作正常,除了它呈现“鬼墙”(轻灰色笔画)的事实,就像在这张图片中
如果我瞥一眼边缘,我可以看到,例如,单元格[3][3]
应该只有顶部和左侧墙,因为它的边缘是[23, -1, -1, 32]
。我确信错误在于我如何移动这一点,但我无法确定问题。
最小的例子:https://stackblitz.com/edit/js-ys9a1j
在最小的例子中,图形不是随机的,而是以一种方式设计,结果应该包含在所有块中,只有底壁和左壁([-1,-1,1,1])
这里有一个逻辑问题:你是独立定义每个单元格的四个边。
例如,如果我们将单元格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
。
经过测试,我发现图形的想法实际上也需要一个查找方法,或者它只能在两个方向上进行...
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>
我发现了这个问题,与朋友一起查看代码,我们注意到渲染单元格的情况3正在绘制错误的行。这就是代码修复的方式。
感谢Kaiido,我甚至用他的建议解决了浅灰色笔画的问题,将坐标偏移0.5。
case 3:
this._adjustedMoveTo(coords.x, coords.y + size);
(w !== -1) ? this._adjustedLineTo(coords.x, coords.y) : null
break;
}