高级动画
绘制球体
我们将使用一个球体来进行动画研究,所以让我们首先将这个球体绘制到画布上。以下代码将为我们做好准备。
html
<canvas id="canvas" width="600" height="300"></canvas>
像往常一样,我们首先需要一个绘图上下文。为了绘制球体,我们将创建一个ball
对象,其中包含属性和一个draw()
方法,用于将其绘制到画布上。
js
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const ball = {
x: 100,
y: 100,
radius: 25,
color: "blue",
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
},
};
ball.draw();
这里没有什么特别的,球体实际上是一个简单的圆形,并借助arc()
方法绘制。
添加速度
现在我们有了球体,我们就可以像在本教程的上一章中学习的那样添加一个基本动画了。同样,window.requestAnimationFrame()
帮助我们控制动画。球体通过向位置添加速度向量而开始移动。对于每一帧,我们还会清除画布以移除先前帧中的旧圆形。
js
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let raf;
const ball = {
x: 100,
y: 100,
vx: 5,
vy: 2,
radius: 25,
color: "blue",
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
},
};
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ball.draw();
ball.x += ball.vx;
ball.y += ball.vy;
raf = window.requestAnimationFrame(draw);
}
canvas.addEventListener("mouseover", (e) => {
raf = window.requestAnimationFrame(draw);
});
canvas.addEventListener("mouseout", (e) => {
window.cancelAnimationFrame(raf);
});
ball.draw();
边界
如果没有边界碰撞检测,我们的球体很快就会超出画布范围。我们需要检查球体的x
和y
位置是否超出画布尺寸,并反转速度向量的方向。为此,我们在draw
方法中添加以下检查
js
if (
ball.y + ball.vy > canvas.height - ball.radius ||
ball.y + ball.vy < ball.radius
) {
ball.vy = -ball.vy;
}
if (
ball.x + ball.vx > canvas.width - ball.radius ||
ball.x + ball.vx < ball.radius
) {
ball.vx = -ball.vx;
}
第一个演示
让我们看看到目前为止它在实际中的效果。
HTML
html
<canvas id="canvas" style="border: 1px solid" width="600" height="300"></canvas>
JavaScript
js
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let raf;
const ball = {
x: 100,
y: 100,
vx: 5,
vy: 2,
radius: 25,
color: "blue",
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
},
};
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ball.draw();
ball.x += ball.vx;
ball.y += ball.vy;
if (
ball.y + ball.vy > canvas.height - ball.radius ||
ball.y + ball.vy < ball.radius
) {
ball.vy = -ball.vy;
}
if (
ball.x + ball.vx > canvas.width - ball.radius ||
ball.x + ball.vx < ball.radius
) {
ball.vx = -ball.vx;
}
raf = window.requestAnimationFrame(draw);
}
canvas.addEventListener("mouseover", (e) => {
raf = window.requestAnimationFrame(draw);
});
canvas.addEventListener("mouseout", (e) => {
window.cancelAnimationFrame(raf);
});
ball.draw();
结果
将鼠标移入画布以开始动画。
加速度
为了使运动更真实,您可以像这样修改速度,例如
js
ball.vy *= 0.99;
ball.vy += 0.25;
这会使垂直速度每一帧都减慢,这样球体最终只会在地板上弹跳。
第二个演示
HTML
html
<canvas id="canvas" style="border: 1px solid" width="600" height="300"></canvas>
JavaScript
js
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let raf;
const ball = {
x: 100,
y: 100,
vx: 5,
vy: 2,
radius: 25,
color: "blue",
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
},
};
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ball.draw();
ball.x += ball.vx;
ball.y += ball.vy;
ball.vy *= 0.99;
ball.vy += 0.25;
if (
ball.y + ball.vy > canvas.height - ball.radius ||
ball.y + ball.vy < ball.radius
) {
ball.vy = -ball.vy;
}
if (
ball.x + ball.vx > canvas.width - ball.radius ||
ball.x + ball.vx < ball.radius
) {
ball.vx = -ball.vx;
}
raf = window.requestAnimationFrame(draw);
}
canvas.addEventListener("mouseover", (e) => {
raf = window.requestAnimationFrame(draw);
});
canvas.addEventListener("mouseout", (e) => {
window.cancelAnimationFrame(raf);
});
ball.draw();
结果
拖尾效果
第三个演示
HTML
html
<canvas id="canvas" style="border: 1px solid" width="600" height="300"></canvas>
JavaScript
js
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let raf;
const ball = {
x: 100,
y: 100,
vx: 5,
vy: 2,
radius: 25,
color: "blue",
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
},
};
function draw() {
ctx.fillStyle = "rgb(255 255 255 / 30%)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ball.draw();
ball.x += ball.vx;
ball.y += ball.vy;
ball.vy *= 0.99;
ball.vy += 0.25;
if (
ball.y + ball.vy > canvas.height - ball.radius ||
ball.y + ball.vy < ball.radius
) {
ball.vy = -ball.vy;
}
if (
ball.x + ball.vx > canvas.width - ball.radius ||
ball.x + ball.vx < ball.radius
) {
ball.vx = -ball.vx;
}
raf = window.requestAnimationFrame(draw);
}
canvas.addEventListener("mouseover", (e) => {
raf = window.requestAnimationFrame(draw);
});
canvas.addEventListener("mouseout", (e) => {
window.cancelAnimationFrame(raf);
});
ball.draw();
结果
添加鼠标控制
第四个演示
HTML
html
<canvas id="canvas" style="border: 1px solid" width="600" height="300"></canvas>
JavaScript
js
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let raf;
let running = false;
const ball = {
x: 100,
y: 100,
vx: 5,
vy: 1,
radius: 25,
color: "blue",
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
},
};
function clear() {
ctx.fillStyle = "rgb(255 255 255 / 30%)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
function draw() {
clear();
ball.draw();
ball.x += ball.vx;
ball.y += ball.vy;
if (
ball.y + ball.vy > canvas.height - ball.radius ||
ball.y + ball.vy < ball.radius
) {
ball.vy = -ball.vy;
}
if (
ball.x + ball.vx > canvas.width - ball.radius ||
ball.x + ball.vx < ball.radius
) {
ball.vx = -ball.vx;
}
raf = window.requestAnimationFrame(draw);
}
canvas.addEventListener("mousemove", (e) => {
if (!running) {
clear();
ball.x = e.clientX;
ball.y = e.clientY;
ball.draw();
}
});
canvas.addEventListener("click", (e) => {
if (!running) {
raf = window.requestAnimationFrame(draw);
running = true;
}
});
canvas.addEventListener("mouseout", (e) => {
window.cancelAnimationFrame(raf);
running = false;
});
ball.draw();
结果
使用鼠标移动球体,并单击释放。