关键词

利用JavaScript实现绘制2023新年烟花的示例代码

下面是在网页中利用JavaScript实现绘制2023新年烟花的完整攻略。

准备工作

在开始编写代码之前,我们需要准备以下工具和环境:

  • 一个文本编辑器,推荐使用 Visual Studio Code
  • 一个浏览器,推荐使用 Chrome
  • 一些基础的 JavaScript 知识,例如函数、变量、事件等

编写HTML结构

首先,我们需要在HTML文件中添加一个canvas标签,并设置宽高,代码如下:

<canvas id="fireworks"></canvas>

添加样式

为了让烟花能够在页面中居中并占据整个窗口,我们需要为 canvas 标签添加一些样式:

canvas {
  display: block;
  margin: auto;
}

编写 JavaScript 代码

接下来,我们就可以编写 JavaScript 代码来实现绘制烟花的功能了。

创建画布

我们需要创建一个画布,获取画布对象,并将其设置为全屏,并且设置画布的宽高为窗口的宽高,不过需要注意, HTML元素的宽高如果通过css设置,那么实际上元素的宽高仍旧是计算机能识别的默认值:

const canvas = document.getElementById('fireworks');
const ctx = canvas.getContext('2d');

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

创建 Firework

创建一个 Firework 对象,用于描述烟花的基本属性,例如位置、颜色、运动轨迹等,代码如下:

class Firework {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    this.color = `hsl(${Math.random() * 360}, 100%, 50%)`;
    this.target = {
      x: Math.random() * canvas.width,
      y: Math.random() * canvas.height
    }
    this.speed = 10;
    this.angle = Math.atan2(this.target.y - this.y, this.target.x - this.x);
    this.gravity = 0.2;
    this.vx = Math.cos(this.angle) * this.speed;
    this.vy = Math.sin(this.angle) * this.speed;
    this.opacity = 1;
    this.trail = [];
  }

  draw() {
    ctx.beginPath();
    ctx.arc(this.x, this.y, 5, 0, Math.PI * 2);
    ctx.fillStyle = this.color;
    ctx.fill();

    // Draw trail
    ctx.globalAlpha = this.opacity;
    for (let i = 0; i < this.trail.length; i++) {
      ctx.beginPath();
      ctx.arc(this.trail[i].x, this.trail[i].y, i * Math.random() * 2, 0, Math.PI * 2);
      ctx.fillStyle = this.color;
      ctx.fill();
    }
  }

  update() {
    // Update position
    this.x += this.vx;
    this.y += this.vy;

    // Update velocity
    this.vy += this.gravity;

    // Update opacity
    this.opacity -= 0.1;

    // Update trail
    this.trail.push({x: this.x, y: this.y});
    if (this.trail.length > 10) {
      this.trail.shift();
    }
  }
}

创建 Explosion

创建一个 Explosion 对象,用于描述烟花爆炸的基本属性,例如位置、颜色、大小等,代码如下:

class Explosion {
  constructor(x, y, color) {
    this.x = x;
    this.y = y;
    this.color = color;
    this.particles = [];

    for (let i = 0; i < 30; i++) {
      this.particles.push(new Particle(this.x, this.y, this.color));
    }
  }

  draw() {
    for (let i = 0; i < this.particles.length; i++) {
      this.particles[i].draw();
    }
  }

  update() {
    for (let i = 0; i < this.particles.length; i++) {
      this.particles[i].update();
    }
  }
}

创建 Particle

创建一个 Particle 对象,用于描述烟花中的粒子,例如位置、大小、速度等,代码如下:

class Particle {
  constructor(x, y, color) {
    this.x = x;
    this.y = y;
    this.color = color;
    this.vx = Math.random() * 10 - 5;
    this.vy = Math.random() * 10 - 5;
    this.size = Math.random() * 3;
    this.gravity = 0.2;
    this.opacity = 1;
  }

  draw() {
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
    ctx.fillStyle = this.color;
    ctx.fill();
  }

  update() {
    this.x += this.vx;
    this.y += this.vy;
    this.vy += this.gravity;
    this.opacity -= 0.05;
    this.size -= 0.05;
  }
}

创建动画

现在,我们需要创建一个动画,用于在画布上不断绘制烟花,代码如下:

let fireworks = [];

function loop() {
  // Clear canvas
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  // Draw fireworks
  for (let i = 0; i < fireworks.length; i++) {
    fireworks[i].draw();
    fireworks[i].update();

    // Explode when reach the target
    if (fireworks[i].y - fireworks[i].target.y > 0) {
      let explosion = new Explosion(fireworks[i].x, fireworks[i].y, fireworks[i].color);
      fireworks.splice(i, 1);
      i--;
      for (let j = 0; j < 10; j++) {
        fireworks.push(new Firework(explosion.x, explosion.y));
      }
    }
  }

  // Generate new firework
  if (Math.random() < 0.2) {
    fireworks.push(new Firework(canvas.width/2, canvas.height));
  }

  requestAnimationFrame(loop);
}

loop();

完整代码

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>2023 New Year Fireworks</title>
  <style>
    canvas {
      display: block;
      margin: auto;
    }
  </style>
</head>
<body>
  <canvas id="fireworks"></canvas>
  <script>
    const canvas = document.getElementById('fireworks');
    const ctx = canvas.getContext('2d');

    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    class Firework {
      constructor(x, y) {
        this.x = x;
        this.y = y;
        this.color = `hsl(${Math.random() * 360}, 100%, 50%)`;
        this.target = {
          x: Math.random() * canvas.width,
          y: Math.random() * canvas.height
        }
        this.speed = 10;
        this.angle = Math.atan2(this.target.y - this.y, this.target.x - this.x);
        this.gravity = 0.2;
        this.vx = Math.cos(this.angle) * this.speed;
        this.vy = Math.sin(this.angle) * this.speed;
        this.opacity = 1;
        this.trail = [];
      }

      draw() {
        ctx.beginPath();
        ctx.arc(this.x, this.y, 5, 0, Math.PI * 2);
        ctx.fillStyle = this.color;
        ctx.fill();

        // Draw trail
        ctx.globalAlpha = this.opacity;
        for (let i = 0; i < this.trail.length; i++) {
          ctx.beginPath();
          ctx.arc(this.trail[i].x, this.trail[i].y, i * Math.random() * 2, 0, Math.PI * 2);
          ctx.fillStyle = this.color;
          ctx.fill();
        }
      }

      update() {
        // Update position
        this.x += this.vx;
        this.y += this.vy;

        // Update velocity
        this.vy += this.gravity;

        // Update opacity
        this.opacity -= 0.1;

        // Update trail
        this.trail.push({x: this.x, y: this.y});
        if (this.trail.length > 10) {
          this.trail.shift();
        }
      }
    }

    class Explosion {
      constructor(x, y, color) {
        this.x = x;
        this.y = y;
        this.color = color;
        this.particles = [];

        for (let i = 0; i < 30; i++) {
          this.particles.push(new Particle(this.x, this.y, this.color));
        }
      }

      draw() {
        for (let i = 0; i < this.particles.length; i++) {
          this.particles[i].draw();
        }
      }

      update() {
        for (let i = 0; i < this.particles.length; i++) {
          this.particles[i].update();
        }
      }
    }

    class Particle {
      constructor(x, y, color) {
        this.x = x;
        this.y = y;
        this.color = color;
        this.vx = Math.random() * 10 - 5;
        this.vy = Math.random() * 10 - 5;
        this.size = Math.random() * 3;
        this.gravity = 0.2;
        this.opacity = 1;
      }

      draw() {
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
        ctx.fillStyle = this.color;
        ctx.fill();
      }

      update() {
        this.x += this.vx;
        this.y += this.vy;
        this.vy += this.gravity;
        this.opacity -= 0.05;
        this.size -= 0.05;
      }
    }

    let fireworks = [];

    function loop() {
      // Clear canvas
      ctx.clearRect(0, 0, canvas.width, canvas.height);

      // Draw fireworks
      for (let i = 0; i < fireworks.length; i++) {
        fireworks[i].draw();
        fireworks[i].update();

        // Explode when reach the target
        if (fireworks[i].y - fireworks[i].target.y > 0) {
          let explosion = new Explosion(fireworks[i].x, fireworks[i].y, fireworks[i].color);
          fireworks.splice(i, 1);
          i--;
          for (let j = 0; j < 10; j++) {
            fireworks.push(new Firework(explosion.x, explosion.y));
          }
        }
      }

      // Generate new firework
      if (Math.random() < 0.2) {
        fireworks.push(new Firework(canvas.width/2, canvas.height));
      }

      requestAnimationFrame(loop);
    }

    loop();
  </script>
</body>
</html>

这样,当我们在浏览器中打开该 HTML 文件时,就能看到一个基于 JavaScript 实现的烟花动画效果了。

示例说明

  1. 修改烟花绘制的速度:将代码中的 speed 值调大或调小即可,例如将 speed 调整为 5,表示烟花的速度变慢了,可以让动画变得更加缓慢。

  2. 修改烟花交互方式:在 Demo 中实现的是以随机方式自动弹出一些烟火, 如果希望增加交互性,可以在页面上添加按钮等交互元素,当用户点击按钮时,触发 JavaScript 代码,从而实现相应的动画效果。

本文链接:http://task.lmcjl.com/news/1220.html

展开阅读全文