如何在不留下痕迹的情况下为 JavaScript/Canvas 中的矩形制作动画?
How do I animate a rectangle in JavaScript/Canvas without leaving a trail?
我正在尝试使用 javascript/canvas 创建一个矩形在屏幕上向下移动的动画。
我遇到的问题是它移动了矩形,但在它后面留下了一条轨迹,而不是仅仅移动了矩形。 (fiddle: 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()
函数简单地在 canvas 上绘制一个矩形。
ctx.fillRect() 文档:https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillRect
选项 1(重置 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(在评论中提到):对动画使用翻译:在这里你一直有相同的路径,这就是为什么你只需要将矩形添加到路径一次。首先平移 canvas 然后绘制矩形。更多关于 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>
我正在尝试使用 javascript/canvas 创建一个矩形在屏幕上向下移动的动画。
我遇到的问题是它移动了矩形,但在它后面留下了一条轨迹,而不是仅仅移动了矩形。 (fiddle: 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()
函数简单地在 canvas 上绘制一个矩形。
ctx.fillRect() 文档:https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillRect
选项 1(重置 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(在评论中提到):对动画使用翻译:在这里你一直有相同的路径,这就是为什么你只需要将矩形添加到路径一次。首先平移 canvas 然后绘制矩形。更多关于 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>