如何在JavaScript/Canvas中动画矩形而不留下痕迹?



我正在尝试使用javascript/canvas创建一个矩形向下移动的动画。

我遇到的问题是,它移动了矩形,但在它后面留下了一个痕迹,而不仅仅是移动矩形。(小提琴:https://jsfiddle.net/winterswebs/hmgfwp9z/116/)

如何在不留下痕迹的情况下动画一个对象?

let v = {
movingObjects: [{
path: new Path2D(),
y: 0,
img: {
width: 100,
height: 100,
}
}],
animationTime: 0,
lastFrameTime: 0,
testingCountOut: 0,
}
const canvas = document.querySelector("#canvas");
const ctx = canvas.getContext("2d");
canvas.width = 400;
canvas.height = 400;
function loop() {
//if (v.testingCountOut >= 10) return;
let now = Date.now();
let delta = v.lastFrameTime == 0 ? 0 : (now - v.lastFrameTime) / 1000;
v.lastFrameTime = now;
draw(delta);
//v.testingCountOut++;
requestAnimationFrame(loop);
}
function draw(delta) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
v.animationTime = Number(v.animationTime) + Number(delta);
let movingObjVY = 100;
let movingObjYPos = v.animationTime * movingObjVY;
v.movingObjects.forEach((element, index) => {
ctx.save();
ctx.beginPath();
v.movingObjects[index].path.rect(
10,
element.y + movingObjYPos,
element.img.width,
element.img.height
);
ctx.fillStyle = "rgba(255,255,255,0.5)";
ctx.fill(v.movingObjects[index].path);
//ctx.strokeStyle = "rgba(0,0,0,1)";
//ctx.stroke(v.movingObjects[index].path);
ctx.restore();
});
}
loop();
body {
background-color: #777;
}
#canvas {
border: 1px solid #000;
}
<canvas id="canvas"></canvas>

每次调用v.movingObjects[index].path.rect();时,您都会向路径添加一个新的矩形,这就是为什么您还可以看到所有先前的矩形。你有两个选择:要么你创建一个新的路径,每次你添加矩形到路径或你摆脱路径,并使用CanvasRenderingContext2D.fillRect()函数简单地画一个矩形在你的画布上。

ctx.fillRect() doc: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillRect

选项1 (reset Path2D):

let v = {
movingObjects: [{
path: new Path2D(),
y: 0,
img: {
width: 100,
height: 100,
}
}],
animationTime: 0,
lastFrameTime: 0,
testingCountOut: 0,
}
const canvas = document.querySelector("#canvas");
const ctx = canvas.getContext("2d");
canvas.width = 400;
canvas.height = 400;
function loop() {
//if (v.testingCountOut >= 10) return;
let now = Date.now();
let delta = v.lastFrameTime == 0 ? 0 : (now - v.lastFrameTime) / 1000;
v.lastFrameTime = now;
draw(delta);
//v.testingCountOut++;
requestAnimationFrame(loop);
}
function draw(delta) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
v.animationTime = Number(v.animationTime) + Number(delta);
let movingObjVY = 100;
let movingObjYPos = v.animationTime * movingObjVY;
v.movingObjects.forEach((element, index) => {
ctx.save();
ctx.beginPath();
v.movingObjects[index].path.rect(
10,
element.y + movingObjYPos,
element.img.width,
element.img.height
);
ctx.fillStyle = "rgba(255,255,255,0.5)";
ctx.fill(v.movingObjects[index].path);
ctx.closePath();
v.movingObjects[index].path = new Path2D();
ctx.restore();
});
}
loop();
body {
background-color: #777;
}
#canvas {
border: 1px solid #000;
}
<canvas id="canvas"></canvas>

选项2 (fillRect):

let v = {
movingObjects: [{
y: 0,
img: {
width: 100,
height: 100,
}
}],
animationTime: 0,
lastFrameTime: 0,
testingCountOut: 0,
}
const canvas = document.querySelector("#canvas");
const ctx = canvas.getContext("2d");
canvas.width = 400;
canvas.height = 400;
function loop() {
//if (v.testingCountOut >= 10) return;
let now = Date.now();
let delta = v.lastFrameTime == 0 ? 0 : (now - v.lastFrameTime) / 1000;
v.lastFrameTime = now;
draw(delta);
//v.testingCountOut++;
requestAnimationFrame(loop);
}
function draw(delta) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
v.animationTime = Number(v.animationTime) + Number(delta);
let movingObjVY = 100;
let movingObjYPos = v.animationTime * movingObjVY;
v.movingObjects.forEach((element, index) => {
ctx.save();
ctx.beginPath();
ctx.fillStyle = "rgba(255,255,255,0.5)";
ctx.fillRect(
10,
element.y + movingObjYPos,
element.img.width,
element.img.height
);
ctx.closePath()
ctx.restore();
});
}
loop();
body {
background-color: #777;
}
#canvas {
border: 1px solid #000;
}
<canvas id="canvas"></canvas>

选项3(在评论中提到):使用翻译动画:这里你有相同的路径整个时间,这就是为什么你只需要添加矩形一次到路径。首先平移画布,然后绘制矩形。关于CanvasRenderingContext2D.translate()的更多信息:https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/translate)

let v = {
movingObjects: [{
path: new Path2D(),
y: 0,
img: {
width: 100,
height: 100,
}
}],
animationTime: 0,
lastFrameTime: 0,
testingCountOut: 0,
}
const canvas = document.querySelector("#canvas");
const ctx = canvas.getContext("2d");
canvas.width = 400;
canvas.height = 400;
function loop() {
//if (v.testingCountOut >= 10) return;
let now = Date.now();
let delta = v.lastFrameTime == 0 ? 0 : (now - v.lastFrameTime) / 1000;
v.lastFrameTime = now;
draw(delta);
//v.testingCountOut++;
requestAnimationFrame(loop);
}
v.movingObjects.forEach((element, index) => {
v.movingObjects[index].path.rect(
10,
element.y,
element.img.width,
element.img.height
);
});
function draw(delta) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
v.animationTime = Number(v.animationTime) + Number(delta);
let movingObjVY = 100;
let movingObjYPos = v.animationTime * movingObjVY;
v.movingObjects.forEach((element, index) => {
ctx.save();
ctx.beginPath();
ctx.translate(0, movingObjYPos)
ctx.fillStyle = "rgba(255,255,255,0.5)";
ctx.fill(v.movingObjects[index].path);
ctx.closePath();
ctx.restore();
});
}
loop();
body {
background-color: #777;
}
#canvas {
border: 1px solid #000;
}
<canvas id="canvas"></canvas>

最新更新