继续扩展三个案例,更全面地展示 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 驱动的动画如何结合用户输入、物理模拟和批量对象控制,创造出丰富的动态视觉表现。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐