我正在网络中使用 Canvas2D 和 (CanvasRenderingContext2D)[https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D] 制作游戏(使用 TypeScript)。我想要实现的是保存画布渲染的当前状态,类似于屏幕截图,并将其存储在内存中。我想要这个,这样我就可以创建我的世界的迷你地图,而无需重新渲染的开销。这是否可行,或者这是否需要 WebGL 渲染器? 谷歌搜索时找不到任何相关内容
我想要实现的一些伪代码
//First we would render the world
//...
//Then save a render of the canvas
var texture = ctx.saveRenderOrSomeShit();
//Render hud
//...
//Render the world as part of the hud to top right or something similar
ctx.fillRect(texture, etc etc etc);
//Done rendering
感谢您的阅读!
ctx.drawImage()
确实接受 HTMLCanvasElement
或 OffscreenCanvas
实例作为输入,因此您可以创建一个这样的画布,在其中绘制,然后将其用作纹理:
const texture = new OffscreenCanvas(50, 50);
const texCtx = texture.getContext("2d");
texCtx.fillStyle = "red";
texCtx.roundRect(0, 0, 50, 50, [30, 10]);
texCtx.fill();
const main = document.querySelector("canvas");
const ctx = main.getContext("2d");
main.addEventListener("mousemove", (evt) => {
ctx.clearRect(0, 0, main.width, main.height);
const x = evt.clientX - main.offsetLeft - texture.width / 2;
const y = evt.clientY - main.offsetTop - texture.height / 2;
ctx.drawImage(texture, x, y);
});
ctx.drawImage(texture, 50, 50);
canvas { border: 1px solid }
<canvas></canvas>
然而,每个纹理有一个完整的画布+ 2D 上下文有点消耗内存,因此您可以从画布中创建
ImageBitmap
对象,但这是异步的,因此您需要提前准备它们。
(async () => {
const main = document.querySelector("canvas");
main.width = 50;
main.height = 50;
const ctx = main.getContext("2d");
ctx.fillStyle = "red";
ctx.roundRect(0, 0, 50, 50, [30, 10]);
ctx.fill();
const texture = await createImageBitmap(main);
main.width = 300;
main.height = 150;
main.addEventListener("mousemove", (evt) => {
ctx.clearRect(0, 0, main.width, main.height);
const x = evt.clientX - main.offsetLeft - texture.width / 2;
const y = evt.clientY - main.offsetTop - texture.height / 2;
ctx.drawImage(texture, x, y);
});
ctx.drawImage(texture, 50, 50);
})();
canvas { border: 1px solid }
<canvas></canvas>
既然您似乎希望将此纹理用作
fillStyle
,那么请注意,您也可以使用画布作为 createPattern()
的源:
const main = document.querySelector("canvas");
main.width = 50;
main.height = 50;
const ctx = main.getContext("2d");
ctx.fillStyle = "red";
ctx.roundRect(0, 0, 50, 50, [30, 10]);
ctx.fill();
const texture = ctx.createPattern(main, "no-repeat");
main.width = 300;
main.height = 150;
ctx.fillStyle = texture;
main.addEventListener("mousemove", (evt) => {
ctx.resetTransform();
ctx.clearRect(0, 0, main.width, main.height);
const x = evt.clientX - main.offsetLeft - 50 / 2;
const y = evt.clientY - main.offsetTop - 50 / 2;
// Patterns position is always relative to the context's CTM
// So we need to transform it rather than just using x, y of our path
ctx.translate(x, y);
ctx.fillRect(0, 0, 50, 50);
});
ctx.translate(50, 50);
ctx.fillRect(0, 0, 50, 50);
canvas { border: 1px solid }
<canvas></canvas>