返回

前端技术指南:学习如何利用Canvas绘制绚烂烟花

前端

序言

时隔半个月,终于又和大家见面了。上一次的demo其实只是使用了canvas最基本的一些东西,并没有涉及到一些比较复杂的应用。这次我们就来实现一个难度稍微大点的canvas,当然,要是能看懂上一篇,那么这次的理解起来也会比较容易。

这次我们来制作一个烟花效果。写烟花效果的人很多,但是我对于他们写的那种效果都不是很满意,因为他们总是喜欢使用一个数组来模拟烟花的爆炸路径,然后按照数组中的路径进行渲染。这种方式很简单,实现起来也非常容易,但是却有一个很大的弊端:你并不能灵活控制烟花爆炸的方向以及烟花的形状。

烟花制作思路

首先,我们先确定一下思路,这部分需要认真看,因为这会影响到后面的代码实现。其实,烟花最难的地方并不是爆炸的实现,而是爆炸后形状的制作。现在,我们假定爆炸后是这样的:

     \ /
      X
     / \

当然,实际情况肯定会比这个复杂得多,但是我们暂且就这样来考虑。那么,我们可以把这个烟花形状分成四个部分:

  • 烟花头部,即字母“X”的部分
  • 烟花左右两侧的线条,即字母“/”的部分
  • 烟花底部的一条线,即字母“\”的部分

接下来,我们需要考虑的是这四个部分中哪一部分是决定了烟花爆炸的形状的,这是整个烟花制作中最关键的问题。

  • 烟花头部是决定了烟花爆炸的中心点,这个中心点的位置决定了烟花爆炸后形状的位置。
  • 烟花左右两侧的线条决定了烟花爆炸后的长度,长度的大小决定了烟花爆炸后有多大。
  • 烟花底部的线条决定了烟花爆炸后的角度,角度的大小决定了烟花爆炸后向哪个方向爆炸。

这样,我们就需要把这三个部分用canvas绘制出来,然后按照爆炸的中心点进行渲染。同时,我们还需要给烟花加入一个运动轨迹,这样烟花就会在空中飞舞,然后在空中爆炸。

代码实现

//获取canvas元素
var canvas = document.getElementById('canvas');
//获取canvas上下文
var ctx = canvas.getContext('2d');

//烟花对象数组
var fireworks = [];

//烟花爆炸后的长度
var explosionLength = 100;

//烟花爆炸后的角度
var explosionAngle = 45;

//烟花运动速度
var speed = 5;

//烟花爆炸颜色
var colors = ['#ff0000', '#ff7f00', '#ffff00', '#00ff00', '#0000ff', '#4b0082', '#8b00ff'];

//初始化烟花对象数组
for (var i = 0; i < 10; i++) {
  //随机生成烟花爆炸的中心点
  var x = Math.random() * canvas.width;
  var y = Math.random() * canvas.height / 2;

  //随机生成烟花运动的速度
  var vx = Math.random() * speed;
  var vy = Math.random() * speed;

  //随机生成烟花爆炸后的长度
  var length = Math.random() * explosionLength;

  //随机生成烟花爆炸后的角度
  var angle = Math.random() * explosionAngle;

  //随机生成烟花爆炸的颜色
  var color = colors[Math.floor(Math.random() * colors.length)];

  //创建烟花对象
  var firework = {
    x: x,
    y: y,
    vx: vx,
    vy: vy,
    length: length,
    angle: angle,
    color: color,
    exploded: false
  };

  //将烟花对象添加到数组中
  fireworks.push(firework);
}

//动画循环
function animate() {
  //清除画布
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  //更新烟花的位置
  for (var i = 0; i < fireworks.length; i++) {
    var firework = fireworks[i];

    firework.x += firework.vx;
    firework.y += firework.vy;

    //如果烟花已经爆炸,则不再更新位置
    if (firework.exploded) {
      continue;
    }

    //如果烟花已经飞出画布,则从数组中移除
    if (firework.x < 0 || firework.x > canvas.width || firework.y < 0 || firework.y > canvas.height) {
      fireworks.splice(i, 1);
      continue;
    }

    //如果烟花已经到达爆炸点,则让烟花爆炸
    if (firework.y >= canvas.height / 2) {
      firework.exploded = true;
    }
  }

  //绘制烟花
  for (var i = 0; i < fireworks.length; i++) {
    var firework = fireworks[i];

    //如果烟花已经爆炸,则绘制爆炸效果
    if (firework.exploded) {
      drawExplosion(firework);
      continue;
    }

    //绘制烟花头部
    ctx.fillStyle = firework.color;
    ctx.beginPath();
    ctx.arc(firework.x, firework.y, 2, 0, 2 * Math.PI);
    ctx.fill();
  }

  //重复动画循环
  requestAnimationFrame(animate);
}

//绘制爆炸效果
function drawExplosion(firework) {
  //计算爆炸中心点
  var x = firework.x;
  var y = firework.y;

  //计算爆炸后的长度
  var length = firework.length;

  //计算爆炸后的角度
  var angle = firework.angle;

  //计算爆炸后的颜色
  var color = firework.color;

  //绘制爆炸头部
  ctx.fillStyle = color;
  ctx.beginPath();
  ctx.arc(x, y, 5, 0, 2 * Math.PI);
  ctx.fill();

  //绘制爆炸左右两侧的线条
  ctx.strokeStyle = color;
  ctx.beginPath();
  ctx.moveTo(x, y);
  ctx.lineTo(x + length * Math.cos(angle), y + length * Math.sin(angle));
  ctx.moveTo(x, y);
  ctx.lineTo(x - length * Math.cos(angle), y + length * Math.sin(angle));
  ctx.stroke();

  //绘制爆炸底部的线条
  ctx.beginPath();
  ctx.moveTo(x, y);
  ctx.lineTo(x, y + length);
  ctx.stroke();
}

//开始动画循环
animate();

效果预览

您可以在以下链接中看到这篇教程的演示效果:

[演示链接]

结语

这篇教程向您展示了如何使用Canvas来创造美丽的烟花效果。您还可以根据自己的需求对代码进行修改,以创建出更复杂、更美丽的烟花效果。如果您有任何问题,请随时在评论区留言。