这个世界多么美丽console.log()是将调试信息输出到Web控制台的好方法。 您可以显示数字,字符串,数组,对象,函数,纯文本,此外,还可以为所有这些添加格式,颜色,背景和许多其他样式……仅此而已? 仅此一种方法就能做到吗? 好吧……简单的平台程序,射线投射算法或组织物理学在控制台中的实现又如何呢?
对于那些来这里只是为了看看的人,我将在开始时留下该演示的链接:
Github: github现场示例: 演示打开页面,按F12键,将控制台扩大,然后转到您感兴趣的演示。 当然,您需要专注于页面,以便能够在控制台中控制图像。
建议在chrome中运行,但是在某些情况下,可能无法支持用于显示图片的字符并将其显示为正方形。 也可以选择自己下载代码,然后将输出字符更改为其他字符。
现在,有关此内容的更多信息
控制台作为画布
让我们来看一下console.log()方法和整个控制台,不是作为调试工具,而是作为画布。 是的,作为一个我们可以画一点甚至使其移动的地方。 此外,没有人取消Unicode字符。
我在控制台中实现了“绘图”方法,例如使用画布的方法。 但是与真实的画布相比,控制台的输出以及其重绘具有很大的局限性,但遗憾的是无法绕开(至少我认为是这样)。 关于他们的顺序。
像素大小
在画布上绘画时,我们正在处理像素,该像素在您的显示器上具有大小,注意力,像素! 当显示在控制台中时,“像素”的概念稍有不同。 是的,相对于控制台,这是它的特殊像素,但是相对于真实像素,它只是一个特殊字符,例如这样吗? 但是对字符有一些限制,或者是一个建议:它的高度应等于控制台中换行符的高度。 但这只是在我们想要获得尽可能美丽的图画的情况下。
重画
这是主要问题,因为 控制台并非旨在频繁更新数据。 我们把它们带到那里,演绎并演绎。 有console.clear()可以清除它,但是我认为它很少使用。 哦,是的,但在我的情况下却不是,因为一切都基于您需要不断清理它并再次显示文本的事实。 这只是一个console.clear()导致其完全过载,并伴有毫秒闪烁。 而且,如果您需要以一定的频率不断地重新绘制它,那么过敏症患者最好不要看它。 但不幸的是,对此无能为力。
色泽
正如我在开始时所写的那样,可以将格式应用于输出,但就我而言,我决定不满足于黑白图像,这要归功于广泛的Unicode字符选择。
可以在实时示例中看到更详细的限制,这些示例是我在本文结尾处留下的链接。 您已经熟悉它们,但是现在我将描述绘制过程本身。 我在一个小型库中设计了所有这些内容,最后通过该库实现了简单的游戏和Raycasting算法
我们在控制台中绘制
我采用了方法的名称,以及画布上的绘制过程(稍后我将描述原因),这就是最终的结果
engine.jsconst canvas = { width: 70, height: 40, getContext(type) { if (type != '2d') { return console.log('Only 2d'); } return new Context2D(type); } } class Context2D { constructor(type) { this.fillStyle = '?'; this.emptyStyle = '?'; this.map = []; for (let i = 0; i < canvas.height; i++) { this.map[i] = []; for (let j = 0; j < canvas.width; j++) { this.map[i][j] = this.emptyStyle; } } this.path = []; this.clear(); } fillRect(x, y, width, height) { for (let i = y; i < y + height; i++) { for (let j = x; j < x + width; j++) { if (!this.map[i]) break; this.map[i][j] = this.fillStyle; } } this.draw(); } strokeRect(x, y, width, height) { for (let j = x; j < x + width; j++) { this.map[y][j] = this.fillStyle; this.map[y + height - 1][j] = this.fillStyle; } for (let i = y + 1; i < y + height - 1; i++) { this.map[i][x] = this.fillStyle; this.map[i][x + width - 1] = this.fillStyle; } this.draw(); } clearRect(x, y, width, height) { for (let i = y; i < y + height; i++) { for (let j = x; j < x + width; j++) { this.map[i][j] = this.emptyStyle; } } this.draw(); } beginPath() { this.path = []; } moveTo(x, y) { this.path.push([Math.round(x), Math.round(y), true]); } lineTo(x, y) { this.path.push([Math.round(x), Math.round(y)]); } closePath() { if (!this.path.length) return false this.path.push([this.path[0][0], this.path[0][1]]); } stroke() { const path = this.path; for (let i = 0; i < path.length - 1; i++) { const x0 = path[i][0]; const y0 = path[i][1]; const x1 = path[i+1][0]; const y1 = path[i+1][1]; this.fillPixel(x1, y1); if (path[i+1][2]) continue; const deltaX = Math.abs(x1 - x0); const deltaY = Math.abs(y1 - y0); const signX = x0 < x1 ? 1 : -1; const signY = y0 < y1 ? 1 : -1; let error = deltaX - deltaY; let x = x0; let y = y0; while(x !== x1 || y !== y1) { this.fillPixel(x, y) const error2 = error * 2; if (error2 > -deltaY) { error -= deltaY; x += signX; } if (error2 < deltaX) { error += deltaX; y += signY; } } } this.draw(); } fillPixel(x, y) { if (!this.map[y]) return false; this.map[y][x] = this.fillStyle; } arc(x1, y1, r) { let x = 0; let y = r; let delta = 1 - 2 * r; let error = 0; while (y >= 0) { this.moveTo(x1 + x, y1 + y); this.moveTo(x1 + x, y1 - y); this.moveTo(x1 - x, y1 + y); this.moveTo(x1 - x, y1 - y); error = 2 * (delta + y) - 1; if (delta < 0 && error <= 0) { delta += 2 * ++x + 1; continue; } if (delta > 0 && error > 0) { delta -= 2 * --y + 1; continue; } delta += 2 * (++x - y--); } this.draw() } draw() { this.clear();
现在,我们将此文件包含在html文件中,打开控制台并可以尝试几种方法
canvas.width = 70 canvas.height = 30 const ctx = canvas.getContext('2d') ctx.beginPath() ctx.moveTo(30, 5) ctx.lineTo(30, 25) ctx.moveTo(30, 15) ctx.lineTo(35, 13) ctx.lineTo(38, 13) ctx.lineTo(40, 16) ctx.lineTo(40, 25) ctx.stroke()
这是结果

输出是我构想的图像,所有内容均按坐标绘制,并类似于画布。
很酷的例子
我的计划是使尽可能简单的将常规画布游戏转移到控制台游戏中成为可能。 为此,我实现了相同的方法,只进行了最小的更改。 这是什么意思? 而且,对于任何游戏的实现,我都可以在画布上完成,因此,我更正了几行代码,并从控制台开始!
其实这就是我所做的。 对我来说,第一件事(除了可以在控制台周围移动的小方块之外)是实现Raycasting算法
我没有编写算法本身,而只是
在这里借用了它,更改了几行之后,我在控制台中启动了它。

看起来不错,不是吗?
这是我转移到控制台后获得的更多屏幕截图。
蛇类
可能被抽动甚至撕裂的组织物理同样,这种蛇和组织物理的实现不是我的,我只是将其修改为控制台。 在源文件中,我保留了原始源的链接。