javascript - 清除画布对象的先前位置而不是整个画布
问题描述
我相信有一个逻辑错误,我的逻辑是为了找到我的画布对象的先前坐标,一个移动图像,并删除它之前绘制的帧,这样它就不会在每次绘制时都复制图像到画布上。
下面有一个可重现的演示,我在我认为出现问题的地方添加了评论。
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>
解决方案
仅清除正在更改的画布子集似乎是合乎逻辑的,但通常的方法是每帧清除并重绘整个画布。汽车移动后,需要填充其下方已清除的背景,并且尝试仅重绘该子集将导致视觉伪影和一般的麻烦。清除屏幕的一小部分是过早的优化。
画布无法跟踪像素以外的任何内容,因此动画更像是固定帧的翻书,而不像纸板剪裁动画,其中相同的纸板移动并相互重叠。
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>
推荐阅读
- java - 从 USB 密钥运行 Eclipse:java 环境错误
- postgresql - 无法将 .ddl 文件导入 postgress 服务器
- batch-file - 通过所有子文件夹运行 Batch FOR LOOP
- postgresql - 使用时间戳列索引和 GREATEST 函数的 PostgreSQL 查询优化
- php - 使用递归 php 函数构建数组
- php - 如何过滤使用 foreach 循环生成的数组的输出
- vuejs2 - I have error importing lodash in vue file
- python - 如何从查询中捕获值并将其用作另一个查询中的值
- postgresql - Why creation date for PostgreSQL tables is null?
- javascript - 如何在jquery中更改悬停事件