canvas 中的多个圆圈动画

Animating multiple circles in a canvas

我正在尝试在 canvas 中制作动画:这里,必须绘制一个带编号的圆圈,并从左向右移动一次,在到达动画结束时立即消失。

现在我设法在循环中为它制作动画,但我需要同时(或设置延迟)为多个编号的圆圈制作动画,在不同的行中分层(改变 y 位置),这样它们就不会重叠。

知道我该如何管理吗?我的 JS 代码如下:

// Single Animated Circle - Get Canvas element by Id
var canvas = document.getElementById("canvas");

// Set Canvas dimensions
canvas.width = 300;
canvas.height = 900;

// Get drawing context
var ctx = canvas.getContext("2d");

// Radius
var radius = 13;
// Starting Position
var x = radius;
var y = radius;

// Speed in x and y direction
var dx = 1;
var dy = 0;

// Generate random number
var randomNumber = Math.floor(Math.random() * 60) + 1;

if (randomNumber > 0 && randomNumber <= 10) {
  ctx.strokeStyle = "#0b0bf1";
} else if (randomNumber > 10 && randomNumber <= 20) {
  ctx.strokeStyle = "#f10b0b";
} else if (randomNumber > 20 && randomNumber <= 30) {
  ctx.strokeStyle = "#0bf163";
} else if (randomNumber > 30 && randomNumber <= 40) {
  ctx.strokeStyle = "#f1da0b";
} else if (randomNumber > 40 && randomNumber <= 50) {
  ctx.strokeStyle = "#950bf1";
} else if (randomNumber > 50 && randomNumber <= 60) {
  ctx.strokeStyle = "#0bf1e5";
}

function animate3() {
  requestAnimationFrame(animate3);

  ctx.clearRect(0, 0, 300, 900);

  if (x + radius > 300 || x - radius < 0) {
    x = radius;
  }

  x += dx;

  ctx.beginPath();
  ctx.arc(x, y, 12, 0, Math.PI * 2, false);
  ctx.stroke();
  ctx.fillText(randomNumber, x - 5, y + 3);
}

// Animate the Circle

animate3();
<canvas id="canvas"></canvas>

我在这里将您的示例代码转换为 class ...
我们将所有数据作为参数传递,您可以看到在构造函数中,我简化了很多代码以使其非常简短,但是您所做的所有相同绘图都在 draw 函数中

然后我们需要做的就是创建这个 class 的实例并在您已有的 animate3 循环中调用绘制函数。

您在半径上有一个硬编码值:
ctx.arc(x, y, 12, 0, Math.PI * 2, false)
我认为这是一个错误并在我的代码中修复它

var canvas = document.getElementById("canvas");
canvas.width = canvas.height = 300;
var ctx = canvas.getContext("2d");

class Circle {
  constructor(data) {
    this.data = data
  }

  draw() {
    if (this.data.x + this.data.radius > 300 || this.data.x - this.data.radius < 0) {
      this.data.x = this.data.radius;
    }
    this.data.x += this.data.dx;

    ctx.beginPath();
    ctx.arc(this.data.x, this.data.y, this.data.radius, 0, Math.PI * 2, false);
    ctx.stroke();
    ctx.fillText(this.data.number, this.data.x - 5, this.data.y + 3);
  }
}

circles = []
circles.push(new Circle({radius:13, x: 10, y: 15, dx: 1, dy: 0, number: "1"}))
circles.push(new Circle({radius:10, x: 10, y: 50, dx: 2, dy: 0, number: "2"}))


function animate3() {
  requestAnimationFrame(animate3);
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  circles.forEach(item => item.draw());
}
animate3();
<canvas id="canvas"></canvas>

代码应该很容易理解,如果您有任何问题,请告诉我

这是一个不使用 类 并将动画逻辑与更新分开的解决方案 - 如果您想更精确地控制时间,这会很有用。

// Some helper functions
const clamp = (number, min, max) => Math.min(Math.max(number, min), max);

// Choose and remove random member of arr with equal probability 
const takeRandom = arr => arr.splice(parseInt(Math.random() * arr.length), 1)[0]

// Call a function at an interval, passing the amount of time that has passed since the last call
function update(callBack, interval) {
  let now = performance.now();
  let last;
  setInterval(function() {
    last = now;
    now = performance.now();
    callBack((now - last) / 1000);
  })
}

const settings = {
  width: 300,
  height: 150,
  radius: 13,
  gap: 5,
  circles: 5,
  maxSpeed: 100,
  colors: ["#0b0bf1", "#f10b0b", "#0bf163", "#f1da0b", "#950bf1", "#0bf1e5"]
};
const canvas = document.getElementById("canvas");
canvas.width = settings.width;
canvas.height = settings.height;
const ctx = canvas.getContext("2d");

// Set circle properties
const circles = [...Array(settings.circles).keys()].map(i => ({
  number: i + 1,
  x: settings.radius,
  y: settings.radius + (settings.radius * 2 + settings.gap) * i,
  radius: settings.radius,
  dx: settings.maxSpeed * Math.random(), // This is the speed in pixels per second
  dy: 0,
  color: takeRandom(settings.colors)
}));

function drawCircle(circle) {
  ctx.strokeStyle = circle.color;
  ctx.beginPath();
  ctx.arc(circle.x, circle.y, circle.radius, 0, Math.PI * 2, false);
  ctx.stroke();
  ctx.fillText(circle.number, circle.x - 5, circle.y + 3);
}

function updateCircle(circle, dt) {
  // Update a circle's position after dt seconds
  circle.x = clamp(circle.x + circle.dx * dt, circle.radius + 1, settings.width - circle.radius - 1);
  circle.y = clamp(circle.y + circle.dy * dt, circle.radius + 1, settings.height - circle.radius - 1);
}

function animate() {
  ctx.clearRect(0, 0, settings.width, settings.height);
  circles.forEach(drawCircle);
  requestAnimationFrame(animate);
}

update(dt => circles.forEach(circle => updateCircle(circle, dt)), 50);
animate();
<canvas id="canvas" style="border: solid 1px black"></canvas>