如何将当前 Canvas 2D 状态保存为内存中的纹理,然后再渲染?

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

我正在网络中使用 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

感谢您的阅读!

typescript canvas 2d game-development
1个回答
0
投票

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>

© www.soinside.com 2019 - 2024. All rights reserved.