分享几个前端烟花代码

利用caves生成烟花效果

整体设计思路是创建一个动态的烟花效果,通过不断的创建和更新粒子来模拟烟花爆炸和消散的过程。使用canvas进行图形绘制,利用JavaScript的类和对象来管理粒子和烟花的状态,通过requestAnimationFrame实现流畅的动画效果。

剖析源码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>随机烟花效果</title>
    <style>
        body {
      
      
            margin: 0;
            padding: 0;
            background: black;
            overflow: hidden;
        }
        canvas {
      
      
            display: block;
        }
    </style>
</head>
<body>
<canvas id="fireworksCanvas"></canvas>
<script>
    // 获取canvas元素并设置其宽高
    const canvas = document.getElementById('fireworksCanvas');
    const ctx = canvas.getContext('2d');

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

    // 生成随机数
    function random(min, max) {
      
      
        return Math.random() * (max - min) + min;
    }

    // 粒子类
    class Particle {
      
      
        constructor(x, y, color) {
      
      
            this.x = x;
            this.y = y;
            this.color = color;
            this.radius = random(2, 5);// 粒子的半径,随机生成2到5之间
            this.opacity = 1;// 粒子的不透明度
            this.velocity = {
      
      // 粒子的速度
                x: random(-5, 5),
                y: random(-5, -20)
            };
        }

        // 绘制粒子的方法
        draw() {
      
      
            ctx.beginPath();
            ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
            ctx.fillStyle = `rgba(${ 
        this.color.r}, ${ 
        this.color.g}, ${ 
        this.color.b}, ${ 
        this.opacity})`;
            ctx.fill();
        }

        // 更新粒子状态的方法
        update() {
      
      
            this.x += this.velocity.x;
            this.y += this.velocity.y;
            this.velocity.y += 0.1; // 模拟重力效果
            this.opacity -= 0.01;// 粒子逐渐消失的效果
            this.draw();
        }
    }

    // 烟花类
    class Firework {
      
      
        constructor(x, y) {
      
      
            this.particles = [];
            const colors = ["255,0,0", "0,255,0", "0,0,255", "255,255,0", "0,255,255", "255,0,255"];
            for (let i = 0; i < 100; i++) {
      
      
                // 创建粒子并赋予随机颜色
                const color = new Color(parseInt(colors[(Math.random() * colors.length) | 0]), 255, 255);
                this.particles.push(new Particle(x, y, color));
            }
        }

        // 更新烟花中所有粒子的状态
        update() {
      
      
            this.particles.forEach(particle => particle.update());
            this.particles = this.particles.filter(particle => particle.opacity > 0);
        }
    }

    // 颜色类
    class Color {
      
      
        constructor(r, g, b) {
      
      
            this.r = r;
            this.g = g;
            this.b = b;
        }
    }

    // 存储所有烟花的数组
    let fireworks = [];

    // 触发烟花爆炸的方法
    function explodeFirework() {
      
      
        const x = random(0, canvas.width);
        const y = canvas.height;
        fireworks.push(new Firework(x, y));
    }

    // 动画渲染的方法
    function animate() {
      
      
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        fireworks.forEach(firework => firework.update());
        fireworks = fireworks.filter(firework => firework.particles.length > 0);

        if (Math.random() < 0.05) {
      
       // 有5%的概率触发新的烟花
            explodeFirework();
        }

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

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

设计思路:

  1. 初始化环境
    • 使用<canvas>元素作为画布,通过JavaScript来绘制烟花效果。
    • 设置画布的宽高为浏览器窗口的宽高,以便烟花效果能够覆盖整个可视区域。
  2. 定义辅助函数和类
    • random(min, max):一个简单的辅助函数,用于生成指定范围内的随机数,这在创建烟花效果时用于随机化粒子的属性。
    • Particle类:代表烟花爆炸后产生的单个粒子。粒子具有位置、颜色、大小、速度和不透明度等属性。
    • Firework类:代表一个完整的烟花,由多个Particle实例组成。
    • Color类:用于存储颜色信息。
  3. 创建烟花
    • 在一个数组fireworks中存储所有烟花实例。
    • 通过explodeFirework函数在画布的随机位置创建一个新的烟花。
  4. 动画循环
    • 使用requestAnimationFrame创建一个动画循环,这个函数会在浏览器准备好绘制下一帧时调用提供的回调函数。
    • 在每次动画帧中,更新所有烟花的状态,并清除画布上的旧内容。
  5. 更新和渲染
    • animate函数中,遍历fireworks数组,更新每个烟花中的粒子状态,并绘制到画布上。
    • 粒子状态更新包括位置的改变、速度的调整(模拟重力)、不透明度的减少(模拟烟花逐渐消失的效果)。
    • 移除不透明的粒子,以减少计算量并避免内存泄漏。

代码详细讲解:

  1. HTML结构

    • <canvas id="fireworksCanvas"></canvas>:定义了一个画布元素,用于绘制烟花效果。
  2. CSS样式

    • 设置bodycanvas的样式,确保画布覆盖整个窗口,并且没有滚动条。
  3. JavaScript代码
    a. 初始化

    const canvas = document.getElementById('fireworksCanvas');
    const ctx = canvas.getContext('2d');
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    
    • 获取画布元素并设置其宽高。
      b. 辅助函数
    function random(min, max) {
          
          
        return Math.random() * (max - min) + min;
    }
    
    • 生成一个在minmax之间的随机数。
      c. 粒子类
    class Particle {
          
          
        // ...
    }
    
    • 包含粒子的属性和方法,用于绘制和更新粒子状态。
      d. 烟花类
    class Firework {
          
          
        // ...
    }
    
    • 包含一个烟花所需的所有粒子,并负责更新它们。
      e. 颜色类
    class Color {
          
          
        // ...
    }
    
    • 用于表示粒子的颜色。
      f. 动画循环
    function animate() {
          
          
        // ...
        requestAnimationFrame(animate);
    }
    animate();
    
    • 清除画布、更新烟花状态、检查并触发新的烟花,然后请求下一帧。
接下来分享几个基于以上思路实现的烟花代码:
案例1:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>随机烟花效果</title>
    <style>
        body {
      
      
            margin: 0;
            padding: 0;
            background: black;
            overflow: hidden;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
        }
        canvas {
      
      
            display: block;
        }
        #congrats {
      
      
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: #ff00ff; /* 紫色 */
            font-size: 3em;
            opacity: 0;
            transition: opacity 2s ease-in-out;
            pointer-events: none;
            white-space: nowrap;
            font-family: 'Arial Black', sans-serif;
            text-shadow: 0 0 5px #ffffff, 0 0 10px #ffffff, 0 0 20px #ff00ff, 0 0 30px #ff00ff, 0 0 40px #ff00ff, 0 0 50px #ff00ff, 0 0 75px #ff00ff;
            animation: flash 3s ease-in-out infinite;
        }
        @keyframes flash {
      
      
            0%, 100% {
      
       opacity: 0; }
            50% {
      
       opacity: 1; }
        }
    </style>
</head>
<body>
<canvas id="fireworksCanvas"></canvas>
<div id="congrats">文本</div>
<script>
    const canvas = document.getElementById('fireworksCanvas');
    const ctx = canvas.getContext('2d');
    const congrats = document.getElementById('congrats');

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

    function random(min, max) {
      
      
        return Math.random() * (max - min) + min;
    }

    function randomColor() {
      
      
        return {
      
      
            r: Math.floor(random(0, 255)),
            g: Math.floor(random(0, 255)),
            b: Math.floor(random(0, 255))
        };
    }

    class Particle {
      
      
        constructor(x, y, color) {
      
      
            this.x = x;
            this.y = y;
            this.color = color;
            this.radius = random(2, 5);
            this.opacity = 1;
            this.velocity = {
      
      
                x: random(-5, 5),
                y: random(-20, -5)
            };
        }

        draw() {
      
      
            ctx.beginPath();
            ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
            ctx.fillStyle = `rgba(${ 
        this.color.r}, ${ 
        this.color.g}, ${ 
        this.color.b}, ${ 
        this.opacity})`;
            ctx.fill();
        }

        update() {
      
      
            this.x += this.velocity.x;
            this.y += this.velocity.y;
            this.velocity.y += 0.1; // gravity
            this.opacity -= 0.01;
            if (this.opacity > 0) {
      
      
                this.draw();
            }
        }
    }

    class Firework {
      
      
        constructor(x, y) {
      
      
            this.particles = [];
            for (let i = 0; i < 100; i++) {
      
      
                const color = randomColor();
                this.particles.push(new Particle(x, y, color));
            }
        }

        update() {
      
      
            this.particles.forEach(particle => particle.update());
            this.particles = this.particles.filter(particle => particle.opacity > 0);
        }
    }

    let fireworks = [];

    function explodeFirework() {
      
      
        const x = random(0, canvas.width);
        const y = canvas.height;
        fireworks.push(new Firework(x, y));
        displayText("写下你想显示的文本");
    }

    function displayText(text) {
      
      
        congrats.textContent = text;
        congrats.style.opacity = 1;
        setTimeout(() => {
      
      
            congrats.style.opacity = 0;
        }, 2000);
    }

    function animate() {
      
      
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        fireworks.forEach(firework => firework.update());
        fireworks = fireworks.filter(firework => firework.particles.length > 0);

        if (Math.random() < 0.05) {
      
      
            explodeFirework();
        }

        requestAnimationFrame(animate);
    }

    animate();
</script>
</body>
</html>
案例2:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>烟花效果思路原型</title>
<style>
  body, html {
      
      
    margin: 0;
    padding: 0;
    overflow: hidden;
    background-color: black;
  }
  .firework {
      
      
    position: absolute;
    bottom: 0;
    width: 5px;
    height: 5px;
    background-color: white;
    border-radius: 50%;
  }
  .particle {
      
      
    position: absolute;
    border-radius: 50%;
    background-color: white;
  }
</style>
</head>
<body>
<script>
  function launchFirework() {
      
      
    const firework = document.createElement('div');
    firework.classList.add('firework');
    firework.style.left = Math.random() * window.innerWidth + 'px';
    document.body.appendChild(firework);

    const height = Math.random() * (window.innerHeight - 100) + 100;
    const duration = Math.random() * 3000 + 2000;

    firework.animate([
      {
      
       transform: 'translateY(0px)' },
      {
      
       transform: `translateY(-${ 
        height}px)` }
    ], {
      
      
      duration: duration,
      easing: 'ease-out',
      fill: 'forwards'
    });

    setTimeout(() => {
      
      
      explodeFirework(firework, height);
      document.body.removeChild(firework);
    }, duration);
  }

  function explodeFirework(firework, height) {
      
      
    const particlesCount = Math.random() * 50 + 20;
    for (let i = 0; i < particlesCount; i++) {
      
      
      const particle = document.createElement('div');
      particle.classList.add('particle');
      particle.style.left = firework.offsetLeft + 'px';
      particle.style.bottom = window.innerHeight - height + 'px';
      particle.style.width = particle.style.height = Math.random() * 5 + 'px';
      document.body.appendChild(particle);

      const angle = Math.random() * Math.PI * 2;
      const distance = Math.random() * 100;
      const duration = Math.random() * 2000 + 1000;

      particle.animate([
        {
      
       transform: 'translate(0, 0) scale(1)' },
        {
      
       transform: `translate(${ 
        distance * Math.cos(angle)}px,${ 
        distance * Math.sin(angle)}px) scale(0)` }
      ], {
      
      
        duration: duration,
        easing: 'ease-out',
        fill: 'forwards'
      });

      setTimeout(() => {
      
      
        document.body.removeChild(particle);
      }, duration);
    }
  }

  function randomFireworks() {
      
      
    setInterval(() => {
      
      
      const delay = Math.random() * 1000;
      setTimeout(launchFirework, delay);
    }, 500);
  }

  randomFireworks();
</script>
</body>
</html>
案例3:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>烟花效果原型</title>
<style>
  body, html {
      
      
    margin: 0;
    padding: 0;
    overflow: hidden;
  }
  canvas {
      
      
    background: black;
  }
</style>
</head>
<body>
<canvas id="fireworks"></canvas>
<script>
// 获取canvas元素并设置其宽高
const canvas = document.getElementById('fireworks');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

// 烟花粒子类
class Particle {
      
      
  constructor(x, y, color) {
      
      
    this.x = x;
    this.y = y;
    this.color = color;
    this.velocity = {
      
      
      x: (Math.random() - 0.5) * 5,
      y: (Math.random() - 0.5) * 5
    };
    this.alpha = 1;
  }

  draw() {
      
      
    ctx.save();
    ctx.globalAlpha = this.alpha;
    ctx.beginPath();
    ctx.fillStyle = this.color;
    ctx.arc(this.x, this.y, 3, 0, Math.PI * 2, false);
    ctx.fill();
    ctx.restore();
  }

  update() {
      
      
    this.velocity.y += 0.1; // 加速度模拟重力
    this.x += this.velocity.x;
    this.y += this.velocity.y;
    this.alpha -= 0.015; // 粒子渐隐效果

    // 检查粒子是否超出屏幕
    if (this.x < 0 || this.x > canvas.width || this.y < 0 || this.y > canvas.height) {
      
      
      this.alpha = 0; // 将alpha设置为0来移除粒子
    }
  }
}

// 烟花类
class Firework {
      
      
  constructor() {
      
      
    this.x = Math.random() * canvas.width;
    this.y = canvas.height;
    this.color = `hsl(${ 
        Math.random() * 360}, 100%, 50%)`;
    const maxInitialVelocity = -Math.sqrt(2 * 0.1 * canvas.height); // 最大初始速度
    // 定义最大高度和最小高度
    const maxHeight = 1;
    const minHeight = 0.4;

    this.velocity = {
      
      
      x: (Math.random() - 0.5) * 6,
      y: maxInitialVelocity * (Math.random() * (maxHeight - minHeight) + minHeight) // 随机速度
    };
    this.particles = [];
    this.exploded = false;
  }

  draw() {
      
      
    if (!this.exploded) {
      
      
      ctx.save();
      ctx.beginPath();
      ctx.fillStyle = this.color;
      ctx.arc(this.x, this.y, 4, 0, Math.PI * 2, false);
      ctx.fill();
      ctx.restore();
    }

    this.particles.forEach(particle => particle.draw());
  }

  update() {
      
      
    if (!this.exploded) {
      
      
      this.velocity.y += 0.1; // 加速度模拟重力
      this.x += this.velocity.x;
      this.y += this.velocity.y;

      // 确保烟花不会超出屏幕
      if (this.x < 0 || this.x > canvas.width) {
      
      
        this.velocity.x *= -1;
      }

      if (this.velocity.y >= 0) {
      
      
        this.explode();
      }
    }

    this.particles.forEach((particle, index) => {
      
      
      if (particle.alpha <= 0) {
      
      
        this.particles.splice(index, 1);
      } else {
      
      
        particle.update();
      }
    });
  }

  explode() {
      
      
    for (let i = 0; i < Math.random() * 10 + 40; i++) {
      
      
      this.particles.push(new Particle(this.x, this.y, this.color));
    }
    this.exploded = true;
  }
}

let fireworks = [];

function createFirework() {
      
      
  fireworks.push(new Firework());
}

function animate() {
      
      
  requestAnimationFrame(animate);
  ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  fireworks.forEach((firework, index) => {
      
      
    if (firework.particles.length === 0 && firework.exploded) {
      
      
      fireworks.splice(index, 1);
    } else {
      
      
      firework.update();
      firework.draw();
    }
  });
}

function launchRandomFireworks() {
      
      
  setTimeout(() => {
      
      
    createFirework();
    launchRandomFireworks();
  }, Math.random() * 50);
}

launchRandomFireworks();
animate();
</script>
</body>
案例4:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>烟花效果原型2</title>
<style>
  body, html {
      
      
    margin: 0;
    padding: 0;
    overflow: hidden;
  }
  canvas {
      
      
    background: black;
  }
</style>
</head>
<body>
<canvas id="fireworks"></canvas>
<script>
// 获取canvas元素并设置其宽高
const canvas = document.getElementById('fireworks');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

// 烟花发射时的粒子类
class FireworkParticle {
      
      
  constructor(x, y, color) {
      
      
    this.x = x;
    this.y = y;
    this.color = color;
    this.velocity = {
      
      
      x: (Math.random() - 0.5) * 3,
      y: -(Math.random() * 8 + 5) // 向上的速度
    };
    this.alpha = 1;
  }

  draw() {
      
      
    ctx.save();
    ctx.globalAlpha = this.alpha;
    ctx.beginPath();
    ctx.fillStyle = this.color;
    ctx.arc(this.x, this.y, 2, 0, Math.PI * 2, false);
    ctx.fill();
    ctx.restore();
  }

  update() {
      
      
    this.velocity.y += 0.05; // 较小的重力影响
    this.x += this.velocity.x;
    this.y += this.velocity.y;
    this.alpha -= 0.01; // 较快的渐隐效果

    if (this.alpha <= 0) {
      
      
      this.alpha = 0;
    }
  }
}

// 烟花爆炸时的粒子类
class ExplosionParticle {
      
      
  constructor(x, y, color) {
      
      
    this.x = x;
    this.y = y;
    this.color = color;
    this.velocity = {
      
      
      x: (Math.random() - 0.5) * 6,
      y: (Math.random() - 0.5) * 6
    };
    this.alpha = 1;
  }

  draw() {
      
      
    ctx.save();
    ctx.globalAlpha = this.alpha;
    ctx.beginPath();
    ctx.fillStyle = this.color;
    ctx.arc(this.x, this.y, 3, 0, Math.PI * 2, false);
    ctx.fill();
    ctx.restore();
  }

  update() {
      
      
    // this.velocity.y += 0.05; // 较小的重力影响
    this.x += this.velocity.x;
    this.y += this.velocity.y;
    this.alpha -= 0.015; // 渐隐效果

    if (this.alpha <= 0) {
      
      
      this.alpha = 0;
    }
  }
}

// 烟花类
class Firework {
      
      
  constructor() {
      
      
    this.x = Math.random() * canvas.width;
    this.y = canvas.height;
    this.color = `hsl(${ 
        Math.random() * 360}, 100%, 50%)`;
    const maxInitialVelocity = -Math.sqrt(2 * 0.1 * canvas.height);
    const maxHeight = 1;
    const minHeight = 0.4;

    this.velocity = {
      
      
      x: (Math.random() - 0.5) * 6,
      y: maxInitialVelocity * (Math.random() * (maxHeight - minHeight) + minHeight) // 随机速度
    };
    this.particles = [];
    this.explosionParticles = [];
    this.exploded = false;
  }

  draw() {
      
      
    if (!this.exploded) {
      
      
      ctx.save();
      ctx.beginPath();
      ctx.fillStyle = this.color;
      ctx.arc(this.x, this.y, 4, 0, Math.PI * 2, false);
      ctx.fill();
      ctx.restore();
    }

    this.particles.forEach(particle => particle.draw());
    this.explosionParticles.forEach(particle => particle.draw());
  }

  update() {
      
      
    this.particles.forEach(particle => {
      
      
      particle.update();
      if (particle.alpha <= 0) {
      
      
        const index = this.particles.indexOf(particle);
        if (index > -1) {
      
      
          this.particles.splice(index, 1);
        }
      }
    });

    this.explosionParticles.forEach(particle => {
      
      
      particle.update();
      if (particle.alpha <= 0) {
      
      
        const index = this.explosionParticles.indexOf(particle);
        if (index > -1) {
      
      
          this.explosionParticles.splice(index, 1);
        }
      }
    });

    if (!this.exploded) {
      
      
      this.velocity.y += 0.1; // 加速度模拟重力
      this.x += this.velocity.x;
      this.y += this.velocity.y;

      if (this.x < 0 || this.x > canvas.width) {
      
      
        this.velocity.x *= -1;
      }

      if (this.velocity.y >= 0) {
      
      
        this.explode();
      }
    }
  }

  explode() {
      
      
    for (let i = 0; i < Math.random() * 10 + 40; i++) {
      
      
      this.explosionParticles.push(new ExplosionParticle(this.x, this.y, this.color));
    }
    this.exploded = true;
  }
}

let fireworks = [];

function createFirework() {
      
      
  fireworks.push(new Firework());
}

function animate() {
      
      
  requestAnimationFrame(animate);
  ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  fireworks.forEach((firework, index) => {
      
      
    if (firework.particles.length === 0 && firework.explosionParticles.length === 0 && firework.exploded) {
      
      
      fireworks.splice(index, 1);
    } else {
      
      
      firework.update();
      firework.draw();
    }
  });
}

function launchRandomFireworks() {
      
      
  setTimeout(() => {
      
      
    createFirework();
    launchRandomFireworks();
  }, Math.random() * 50);
}

launchRandomFireworks();
animate();
</script>
</body>
</html>
案例5:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>烟花效果原型</title>
<style>
  body, html {
      
      
    margin: 0;
    padding: 0;
    overflow: hidden;
  }
  canvas {
      
      
    background: black;
  }
</style>
</head>
<body>
<canvas id="fireworks"></canvas>
<script>
// 获取canvas元素并设置其宽高
const canvas = document.getElementById('fireworks');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

// 烟花发射时的粒子类
class FireworkParticle {
      
      
  constructor(x, y, color) {
      
      
    this.x = x;
    this.y = y;
    this.color = color;
    this.velocity = {
      
      
      x: (Math.random() - 0.5) * 3,
      y: -(Math.random() * 8 + 5) // 向上的速度
    };
    this.alpha = 1;
  }

  draw() {
      
      
    ctx.save();
    ctx.globalAlpha = this.alpha;
    ctx.beginPath();
    ctx.fillStyle = this.color;
    ctx.arc(this.x, this.y, 2, 0, Math.PI * 2, false);
    ctx.fill();
    ctx.restore();
  }

  update() {
      
      
    this.velocity.y += 0.05; // 较小的重力影响
    this.x += this.velocity.x;
    this.y += this.velocity.y;
    this.alpha -= 0.01; // 较快的渐隐效果

    if (this.alpha <= 0) {
      
      
      this.alpha = 0;
    }
  }
}

// 烟花爆炸时的粒子类
class ExplosionParticle {
      
      
    constructor(x, y, color, size) {
      
      
    this.x = x;
    this.y = y;
    this.color = color;
    this.velocity = {
      
      
      x: (Math.random() - 0.5) * 6,
      y: (Math.random() - 0.5) * 6
    };
    this.alpha = 1;
    this.size = size; // 粒子大小
  }

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

  update() {
      
      
    this.x += this.velocity.x;
    this.y += this.velocity.y;
    this.alpha -= 0.015; // 渐隐效果

    if (this.alpha <= 0) {
      
      
      this.alpha = 0;
    }
  }
}

// 烟花类
class Firework {
      
      
  constructor() {
      
      
    this.x = Math.random() * canvas.width;
    this.y = canvas.height;
    this.color = this.getRandomColor(); // 使用随机颜色
    const maxInitialVelocity = -Math.sqrt(2 * 0.1 * canvas.height);
    const maxHeight = 1;
    const minHeight = 0.4;

    this.velocity = {
      
      
      x: (Math.random() - 0.5) * 6,
      y: maxInitialVelocity * (Math.random() * (maxHeight - minHeight) + minHeight) // 随机速度
    };
    this.particles = [];
    this.explosionParticles = [];
    this.exploded = false;
  }

  getRandomColor() {
      
      
    const r = Math.floor(Math.random() * 256);
    const g = Math.floor(Math.random() * 256);
    const b = Math.floor(Math.random() * 256);
    return `rgb(${ 
        r}, ${ 
        g}, ${ 
        b})`;
  }

  draw() {
      
      
    if (!this.exploded) {
      
      
      ctx.save();
      ctx.beginPath();
      ctx.fillStyle = this.color;
      ctx.arc(this.x, this.y, 4, 0, Math.PI * 2, false);
      ctx.fill();
      ctx.restore();
    }

    this.particles.forEach(particle => particle.draw());
    this.explosionParticles.forEach(particle => particle.draw());
  }

  update() {
      
      
    this.particles.forEach(particle => {
      
      
      particle.update();
      if (particle.alpha <= 0) {
      
      
        const index = this.particles.indexOf(particle);
        if (index > -1) {
      
      
          this.particles.splice(index, 1);
        }
      }
    });

    this.explosionParticles.forEach(particle => {
      
      
      particle.update();
      if (particle.alpha <= 0) {
      
      
        const index = this.explosionParticles.indexOf(particle);
        if (index > -1) {
      
      
          this.explosionParticles.splice(index, 1);
        }
      }
    });

    if (!this.exploded) {
      
      
      this.velocity.y += 0.1; // 加速度模拟重力
      this.x += this.velocity.x;
      this.y += this.velocity.y;

      if (this.x < 0 || this.x > canvas.width) {
      
      
        this.velocity.x *= -1;
      }

      if (this.velocity.y >= 0) {
      
      
        this.explode();
      }
    }
  }

  explode() {
      
      
    const particleCount = Math.random() * 20 + 30; // 增加粒子数量
    for (let i = 0; i < particleCount; i++) {
      
      
      const size = Math.random() * 3 + 1; // 粒子大小变化
      const newColor = this.getRandomColor(); // 每个粒子可能有不同的颜色
      this.explosionParticles.push(new ExplosionParticle(this.x, this.y, newColor, size));
    }
    this.exploded = true;
  }
}

let fireworks = [];

function createFirework() {
      
      
  fireworks.push(new Firework());
}

function animate() {
      
      
  requestAnimationFrame(animate);
  ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  fireworks.forEach((firework, index) => {
      
      
    if (firework.particles.length === 0 && firework.explosionParticles.length === 0 && firework.exploded) {
      
      
      fireworks.splice(index, 1);
    } else {
      
      
      firework.update();
      firework.draw();
    }
  });
}

function launchRandomFireworks() {
      
      
  setTimeout(() => {
      
      
    createFirework();
    launchRandomFireworks();
  }, Math.random() * 50);
}

launchRandomFireworks();
animate();
</script>
</body>
</html>

以上代码是我给我朋友帮忙时写的,但是后来没用上,现分享出来给大家
未完待续。。。文章不定时更新

猜你喜欢

转载自blog.csdn.net/weixin_74905854/article/details/142443212