点击放烟花效果,随便玩玩

HTML

<!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;
            overflow: hidden;
            background: radial-gradient(circle at center, #000033, #000);
        }
        canvas {
            display: block;
        }
    </style>
</head>
<body>
    <canvas id="fireworksCanvas"></canvas>
    <script src="fireworks.js"></script>
</body>
</html>

 

JS

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

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

window.addEventListener('resize', () => {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
});

const fireworks = [];
const particles = [];

class Firework {
    constructor(x, y, targetX, targetY) {
        this.x = x;
        this.y = y;
        this.targetX = targetX;
        this.targetY = targetY;
        this.speed = 3;
        this.angle = Math.atan2(targetY - y, targetX - x);
        this.distance = Math.hypot(targetX - x, targetY - y);
        this.trail = [];
        this.trailLength = 8;
        this.done = false;
    }

    update() {
        const moveX = Math.cos(this.angle) * this.speed;
        const moveY = Math.sin(this.angle) * this.speed;

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

        this.x += moveX;
        this.y += moveY;

        if (Math.hypot(this.targetX - this.x, this.targetY - this.y) <= this.speed) {
            this.done = true;
            explode(this.targetX, this.targetY);
        }
    }

    draw() {
        ctx.beginPath();
        ctx.moveTo(this.trail[0]?.x || this.x, this.trail[0]?.y || this.y);
        this.trail.forEach(point => ctx.lineTo(point.x, point.y));
        ctx.strokeStyle = 'rgba(255, 255, 255, 0.6)';
        ctx.lineWidth = 2;
        ctx.stroke();

        ctx.beginPath();
        ctx.arc(this.x, this.y, 3, 0, Math.PI * 2);
        ctx.fillStyle = 'white';
        ctx.fill();
    }
}

class Particle {
    constructor(x, y, color) {
        this.x = x;
        this.y = y;
        this.size = Math.random() * 2 + 1;
        this.speedX = Math.random() * 5 - 2.5;
        this.speedY = Math.random() * 5 - 2.5;
        this.gravity = 0.05;
        this.friction = 0.98;
        this.alpha = 1;
        this.decay = Math.random() * 0.02 + 0.01;
        this.color = color;
    }

    update() {
        this.speedX *= this.friction;
        this.speedY *= this.friction;
        this.speedY += this.gravity;
        this.x += this.speedX;
        this.y += this.speedY;
        this.alpha -= this.decay;

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

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

function explode(x, y) {
    const colors = ['#FF1461', '#18FF92', '#5A87FF', '#FBF38C', '#FF61A6'];
    const particleCount = 150;

    for (let i = 0; i < particleCount; i++) {
        const color = colors[Math.floor(Math.random() * colors.length)];
        particles.push(new Particle(x, y, color));
    }
}

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

    fireworks.forEach((firework, index) => {
        firework.update();
        firework.draw();

        if (firework.done) {
            fireworks.splice(index, 1);
        }
    });

    particles.forEach((particle, index) => {
        particle.update();
        particle.draw();

        if (particle.alpha === 0) {
            particles.splice(index, 1);
        }
    });

    requestAnimationFrame(animate);
}

canvas.addEventListener('click', (e) => {
    const x = canvas.width / 2;
    const y = canvas.height;
    const targetX = e.clientX;
    const targetY = e.clientY;
    fireworks.push(new Firework(x, y, targetX, targetY));
});

animate();

 

使用 CSS 渐变背景

烟花尾迹:通过 trail 数组记录烟花移动的历史位置,绘制出渐隐的尾迹效果。

 

 

posted @ 2024-08-20 21:20  最小生成树  阅读(22)  评论(0编辑  收藏  举报