Javascript提高:requestAnimationFrame及圆类的简单动画-B 由Deepseek产生
·
继续扩展三个案例,更全面地展示 requestAnimationFrame 与圆类动画的灵活用法。
案例 4:圆周运动(圆沿圆形轨迹旋转)
圆围绕中心点做匀速圆周运动,利用角度递增并通过 Math.sin/cos 计算位置。
<canvas id="canvas4" width="600" height="400" style="border:1px solid #ccc"></canvas>
<script>
const canvas = document.getElementById('canvas4');
const ctx = canvas.getContext('2d');
class Circle {
constructor(x, y, radius, color) {
this.x = x;
this.y = y;
this.radius = radius;
this.color = color;
}
draw(ctx) {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
ctx.closePath();
}
}
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const orbitRadius = 120; // 圆周半径
let angle = 0;
const speed = 0.02; // 角速度
const circle = new Circle(centerX + orbitRadius, centerY, 20, 'purple');
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 计算新位置
circle.x = centerX + Math.cos(angle) * orbitRadius;
circle.y = centerY + Math.sin(angle) * orbitRadius;
circle.draw(ctx);
angle += speed;
requestAnimationFrame(animate);
}
animate();
</script>
案例 5:多个圆随机弹性碰撞(简单物理模拟)
生成多个圆,赋予随机速度和方向,在矩形边界内弹性碰撞(仅碰撞边界,圆与圆之间不碰撞为保持简洁)。适合展示大量动态对象。
<canvas id="canvas5" width="800" height="400" style="border:1px solid #ccc"></canvas>
<script>
const canvas = document.getElementById('canvas5');
const ctx = canvas.getContext('2d');
class Circle {
constructor(x, y, radius, color, vx, vy) {
this.x = x;
this.y = y;
this.radius = radius;
this.color = color;
this.vx = vx; // x方向速度
this.vy = vy; // y方向速度
}
draw(ctx) {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
ctx.closePath();
}
update(canvasWidth, canvasHeight) {
// 更新位置
this.x += this.vx;
this.y += this.vy;
// 边界反弹
if (this.x + this.radius > canvasWidth) {
this.x = canvasWidth - this.radius;
this.vx = -this.vx;
} else if (this.x - this.radius < 0) {
this.x = this.radius;
this.vx = -this.vx;
}
if (this.y + this.radius > canvasHeight) {
this.y = canvasHeight - this.radius;
this.vy = -this.vy;
} else if (this.y - this.radius < 0) {
this.y = this.radius;
this.vy = -this.vy;
}
}
}
// 生成随机圆
const circles = [];
const numberOfCircles = 15;
for (let i = 0; i < numberOfCircles; i++) {
const radius = 15 + Math.random() * 15;
const x = Math.random() * (canvas.width - 2 * radius) + radius;
const y = Math.random() * (canvas.height - 2 * radius) + radius;
const vx = (Math.random() - 0.5) * 4;
const vy = (Math.random() - 0.5) * 4;
const hue = Math.random() * 360;
const color = `hsl(${hue}, 70%, 60%)`;
circles.push(new Circle(x, y, radius, color, vx, vy));
}
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let circle of circles) {
circle.update(canvas.width, canvas.height);
circle.draw(ctx);
}
requestAnimationFrame(animate);
}
animate();
</script>
案例 6:鼠标吸引与排斥(交互力场)
画布上有一个主圆,鼠标距离它很近时“排斥”或“吸引”圆(这里实现吸引效果:圆会向鼠标光标移动)。同时圆在边界内运动,还受到摩擦力减速。
<canvas id="canvas6" width="600" height="400" style="border:1px solid #ccc"></canvas>
<script>
const canvas = document.getElementById('canvas6');
const ctx = canvas.getContext('2d');
class Circle {
constructor(x, y, radius, color) {
this.x = x;
this.y = y;
this.radius = radius;
this.color = color;
this.vx = 0;
this.vy = 0;
}
draw(ctx) {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
ctx.closePath();
}
applyForce(fx, fy) {
// 质量固定为1,加速度 = 力
this.vx += fx;
this.vy += fy;
}
update(canvasWidth, canvasHeight, friction = 0.98) {
this.vx *= friction;
this.vy *= friction;
this.x += this.vx;
this.y += this.vy;
// 边界反弹(带阻尼,避免逃出)
if (this.x + this.radius > canvasWidth) {
this.x = canvasWidth - this.radius;
this.vx = -this.vx * 0.8;
} else if (this.x - this.radius < 0) {
this.x = this.radius;
this.vx = -this.vx * 0.8;
}
if (this.y + this.radius > canvasHeight) {
this.y = canvasHeight - this.radius;
this.vy = -this.vy * 0.8;
} else if (this.y - this.radius < 0) {
this.y = this.radius;
this.vy = -this.vy * 0.8;
}
}
}
const circle = new Circle(300, 200, 25, 'orange');
let mouseX = canvas.width / 2, mouseY = canvas.height / 2;
let mousePresent = false;
canvas.addEventListener('mousemove', (e) => {
const rect = canvas.getBoundingClientRect();
mouseX = e.clientX - rect.left;
mouseY = e.clientY - rect.top;
mousePresent = true;
});
canvas.addEventListener('mouseleave', () => {
mousePresent = false;
});
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (mousePresent) {
// 计算从圆指向鼠标的向量
let dx = mouseX - circle.x;
let dy = mouseY - circle.y;
let dist = Math.hypot(dx, dy);
if (dist > 0.1) {
// 吸引力大小与距离成反比(模拟磁铁),但限制最大力
let forceMag = Math.min(0.5, 200 / (dist * dist));
let fx = (dx / dist) * forceMag;
let fy = (dy / dist) * forceMag;
circle.applyForce(fx, fy);
}
}
circle.update(canvas.width, canvas.height, 0.98);
circle.draw(ctx);
// 绘制鼠标指针(辅助视觉)
if (mousePresent) {
ctx.beginPath();
ctx.arc(mouseX, mouseY, 8, 0, Math.PI * 2);
ctx.strokeStyle = 'gray';
ctx.setLineDash([4, 6]);
ctx.stroke();
ctx.setLineDash([]);
}
requestAnimationFrame(animate);
}
animate();
</script>
三个新案例总结
| 案例 | 核心机制 | 学习要点 |
|---|---|---|
| 4. 圆周运动 | 角度累加 + 三角函数 | 参数方程控制轨迹,适合旋转、卫星等效果 |
| 5. 多圆弹性碰撞 | 速度向量 + 边界检测 | 批量对象管理、简单物理边界反弹 |
| 6. 鼠标吸引 | 根据鼠标指向施加力场 | 向量运算、力的合成、阻尼摩擦、交互式动画 |
通过这些案例可以进一步了解 requestAnimationFrame 驱动的动画如何结合用户输入、物理模拟和批量对象控制,创造出丰富的动态视觉表现。
更多推荐

所有评论(0)