首页 > 解决方案 > 清除画布对象的先前位置而不是整个画布

问题描述

我相信有一个逻辑错误,我的逻辑是为了找到我的画布对象的先前坐标,一个移动图像,并删除它之前绘制的帧,这样它就不会在每次绘制时都复制图像到画布上。

下面有一个可重现的演示,我在我认为出现问题的地方添加了评论。

var canvas = document.getElementById("c");
var ctx = canvas.getContext("2d");
var the_background = document.getElementById("the_background");

var imgTag = new Image();
var X_POS = canvas.width;
var Y_POS = 0;

imgTag.src = "http://i.stack.imgur.com/Rk0DW.png"; // load image

function animate() {

  /* Error resides from here */
  var coords = {};
  coords.x = Math.floor(this.X_POS - imgTag);
  coords.y = Math.floor(this.Y_POS - imgTag);

  ctx.clearRect(coords.x, coords.y, X_POS, Y_POS);
  /* To here */


  ctx.drawImage(imgTag, X_POS, Y_POS);
  X_POS -= 5;
  if (X_POS > 200) requestAnimationFrame(animate)
}


window.onload = function() {

  ctx.drawImage(the_background, 0, 0, canvas.width, canvas.height);
  animate();
}
html,
body {
  width: 100%;
  height: 100%;
  margin: 0px;
  border: 0;
  overflow: hidden;
  display: block;
}
<html>
<canvas id="c" width="600" height="400"></canvas>

<img style="display: none;" id="the_button" src="https://i.imgur.com/wO7Wc2w.png" />

<img style="display: none;" id="the_background" src="https://img.freepik.com/free-photo/hand-painted-watercolor-background-with-sky-clouds-shape_24972-1095.jpg?size=626&ext=jpg" />

</html>

标签: javascripthtmlcanvas

解决方案


仅清除正在更改的画布子集似乎是合乎逻辑的,但通常的方法是每帧清除并重绘整个画布。汽车移动后,需要填充其下方已清除的背景,并且尝试仅重绘该子集将导致视觉伪影和一般的麻烦。清除屏幕的一小部分是过早的优化。

画布无法跟踪像素以外的任何内容,因此动画更像是固定帧的翻书,而不像纸板剪裁动画,其中相同的纸板移动并相互重叠。

Math.floor(this.X_POS - imgTag)看起来不对 -imgTag是一个图像对象,从数字中减去它没有意义。你可能想x从这里抢夺财产。

用于image.onload确保在运行循环之前实际加载图像。在 DOM 中使用图像标签只是为画布加载图像有点奇怪。我会从 JS 以编程方式执行此操作,这样可以节省一些输入并更容易管理数据。

const loadImg = url => new Promise((resolve, reject) => {
  const img = new Image();
  img.onerror = reject;
  img.onload = () => resolve(img);
  img.src = url;
});

const images = [
  "https://img.freepik.com/free-photo/hand-painted-watercolor-background-with-sky-clouds-shape_24972-1095.jpg?size=626&ext=jpg",
  "http://i.stack.imgur.com/Rk0DW.png",
];
Promise
  .all(images.map(loadImg))
  .then(([backgroundImg, carImg]) => {
    const canvas = document.getElementById("canvas");
    const ctx = canvas.getContext("2d");
    const car = {x: canvas.width, y: 0};
    
    (function update() {
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      
      ctx.drawImage(
        backgroundImg, 0, 0, canvas.width, canvas.height
      );
      ctx.drawImage(
        carImg, car.x, car.y, carImg.width, carImg.height
      );
      car.x -= 5;
      
      if (car.x > 200) {
        requestAnimationFrame(update);
      }
    })();
  })
  .catch(err => console.error(err))
;
<canvas id="canvas" width="600" height="400"></canvas>


推荐阅读