【趣味Html】第11课:动态闪烁发光粒子五角星

发布于:2025-06-05 ⋅ 阅读:(22) ⋅ 点赞:(0)

打造炫酷的动态闪烁发光粒子五角星效果

在这里插入图片描述

前言

在现代Web开发中,视觉效果的重要性不言而喻。今天我们将深入探讨如何使用HTML5 Canvas和JavaScript创建一个令人惊艳的动态闪烁发光粒子五角星效果。这个项目不仅展示了Canvas的强大功能,还涉及了粒子系统、动画循环、数学计算等多个技术要点。

项目概述

我们创建的效果包含以下特性:

  • 🌟 自动旋转的五角星
  • ✨ 动态发光效果(呼吸灯效果)
  • 🎆 粒子系统(从五角星边缘发射粒子)
  • 🎮 鼠标交互(靠近时产生更多粒子)
  • 📱 响应式设计

技术架构

1. 基础结构

<!DOCTYPE html>
<html lang="zh-CN">
<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: #000;
            overflow: hidden;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
        }
        canvas {
            border: 1px solid #333;
        }
    </style>
</head>
<body>
    <canvas id="starCanvas"></canvas>
</body>
</html>

2. 核心类设计

Particle 类(粒子系统)

粒子类是整个效果的核心组件之一,负责创建和管理单个粒子的行为:

class Particle {
    constructor(x, y) {
        this.x = x;                                    // 粒子位置
        this.y = y;
        this.vx = (Math.random() - 0.5) * 2;          // 随机速度
        this.vy = (Math.random() - 0.5) * 2;
        this.life = 1;                                // 生命值
        this.decay = Math.random() * 0.02 + 0.005;    // 衰减速度
        this.size = Math.random() * 3 + 1;            // 粒子大小
        this.color = {                                // 随机颜色
            r: Math.random() * 100 + 155,
            g: Math.random() * 100 + 155,
            b: Math.random() * 100 + 155
        };
    }
    
    update() {
        this.x += this.vx;        // 更新位置
        this.y += this.vy;
        this.life -= this.decay;  // 减少生命值
        this.size *= 0.99;        // 缩小粒子
    }
    
    draw() {
        // 绘制发光效果和粒子本体
    }
}

设计要点:

  • 使用随机值创建自然的粒子运动
  • 生命周期管理确保粒子会自然消失
  • 渐变发光效果增强视觉冲击力
Star 类(五角星系统)

五角星类管理五角星的绘制、旋转和粒子生成:

class Star {
    constructor(x, y, size) {
        this.x = x;
        this.y = y;
        this.size = size;
        this.rotation = 0;              // 旋转角度
        this.glowIntensity = 0;         // 发光强度
        this.glowDirection = 1;         // 发光方向
        this.particles = [];            // 粒子数组
        this.lastParticleTime = 0;      // 上次生成粒子的时间
    }
    
    getStarPoints() {
        // 计算五角星的10个顶点坐标
        const points = [];
        const outerRadius = this.size;
        const innerRadius = this.size * 0.4;
        
        for (let i = 0; i < 10; i++) {
            const angle = (i * Math.PI) / 5 + this.rotation;
            const radius = i % 2 === 0 ? outerRadius : innerRadius;
            const x = this.x + Math.cos(angle) * radius;
            const y = this.y + Math.sin(angle) * radius;
            points.push({ x, y });
        }
        
        return points;
    }
}

核心算法解析

1. 五角星顶点计算

五角星的绘制是基于数学计算的。一个标准五角星有10个顶点(5个外顶点和5个内顶点):

// 五角星顶点计算公式
for (let i = 0; i < 10; i++) {
    const angle = (i * Math.PI) / 5 + this.rotation;  // 每个顶点间隔36度
    const radius = i % 2 === 0 ? outerRadius : innerRadius;
    const x = centerX + Math.cos(angle) * radius;
    const y = centerY + Math.sin(angle) * radius;
}

数学原理:

  • 五角星的外角为36°(2π/10)
  • 内外半径比例约为0.4,创造最佳视觉效果
  • 通过旋转角度实现动态旋转

2. 粒子生成策略

粒子的生成采用了多种策略来创造丰富的视觉效果:

generateParticles() {
    const points = this.getStarPoints();
    
    // 策略1:在五角星边缘生成粒子
    for (let i = 0; i < points.length; i++) {
        const point = points[i];
        const nextPoint = points[(i + 1) % points.length];
        
        // 线性插值在边缘随机位置生成粒子
        const t = Math.random();
        const x = point.x + (nextPoint.x - point.x) * t;
        const y = point.y + (nextPoint.y - point.y) * t;
        
        if (Math.random() < 0.3) {
            this.particles.push(new Particle(x, y));
        }
    }
    
    // 策略2:在顶点生成更多粒子
    for (let i = 0; i < points.length; i += 2) {
        const point = points[i];
        if (Math.random() < 0.5) {
            this.particles.push(new Particle(point.x, point.y));
        }
    }
}

3. 发光效果实现

发光效果通过Canvas的阴影和渐变功能实现:

// 动态发光强度
this.glowIntensity += this.glowDirection * 0.02;
if (this.glowIntensity >= 1 || this.glowIntensity <= 0) {
    this.glowDirection *= -1;  // 反向,创造呼吸效果
}

// 应用发光效果
ctx.shadowColor = `rgba(255, 255, 100, ${this.glowIntensity})`;
ctx.shadowBlur = 20 + this.glowIntensity * 30;

性能优化技巧

1. 粒子生命周期管理

// 高效的粒子清理
this.particles = this.particles.filter(particle => {
    particle.update();
    return particle.life > 0;  // 只保留活着的粒子
});

2. 时间控制的粒子生成

// 避免每帧都生成粒子,控制生成频率
const now = Date.now();
if (now - this.lastParticleTime > 50) {
    this.generateParticles();
    this.lastParticleTime = now;
}

3. 渐进式画布清理

// 使用半透明矩形而非完全清除,创造拖尾效果
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
ctx.fillRect(0, 0, canvas.width, canvas.height);

交互设计

鼠标交互

canvas.addEventListener('mousemove', (e) => {
    const rect = canvas.getBoundingClientRect();
    const mouseX = e.clientX - rect.left;
    const mouseY = e.clientY - rect.top;
    
    stars.forEach(star => {
        const dx = mouseX - star.x;
        const dy = mouseY - star.y;
        const distance = Math.sqrt(dx * dx + dy * dy);
        
        if (distance < 150) {
            // 鼠标靠近时增加粒子生成
            for (let i = 0; i < 3; i++) {
                const angle = Math.random() * Math.PI * 2;
                const radius = Math.random() * star.size;
                const x = star.x + Math.cos(angle) * radius;
                const y = star.y + Math.sin(angle) * radius;
                star.particles.push(new Particle(x, y));
            }
        }
    });
});

响应式设计

window.addEventListener('resize', () => {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    
    // 重新定位五角星
    stars.forEach((star, i) => {
        star.x = canvas.width / 4 + (i * canvas.width / 4);
        star.y = canvas.height / 2 + Math.sin(i * 2) * 100;
    });
});

扩展可能性

1. 颜色主题

可以添加多种颜色主题,让用户选择不同的视觉风格:

const themes = {
    golden: { r: 255, g: 215, b: 0 },
    blue: { r: 100, g: 150, b: 255 },
    purple: { r: 200, g: 100, b: 255 }
};

2. 音频响应

可以集成Web Audio API,让粒子效果响应音频频率:

// 伪代码
const audioContext = new AudioContext();
// 根据音频频率调整粒子生成速度和五角星大小

3. 3D效果

使用WebGL或Three.js可以将效果扩展到3D空间。

总结

这个动态闪烁发光粒子五角星项目展示了现代Web技术的强大能力。通过合理的类设计、数学计算、性能优化和交互设计,我们创造了一个既美观又高效的视觉效果。

关键技术点:

  • Canvas 2D API的高级应用
  • 面向对象的JavaScript设计
  • 数学在图形编程中的应用
  • 性能优化策略
  • 用户交互设计

这个项目不仅可以作为学习Canvas和JavaScript的优秀案例,也可以作为更复杂视觉效果的基础框架。希望这篇博客能够帮助你理解现代Web图形编程的精髓,并激发你创造更多令人惊艳的视觉效果!

源码

<!DOCTYPE html>
<html lang="zh-CN">
<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: #000;
            overflow: hidden;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
        }
        canvas {
            border: 1px solid #333;
        }
    </style>
</head>
<body>
    <canvas id="starCanvas"></canvas>
    
    <script>
        const canvas = document.getElementById('starCanvas');
        const ctx = canvas.getContext('2d');
        
        // 设置画布大小
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        
        // 粒子类
        class Particle {
            constructor(x, y) {
                this.x = x;
                this.y = y;
                this.vx = (Math.random() - 0.5) * 2;
                this.vy = (Math.random() - 0.5) * 2;
                this.life = 1;
                this.decay = Math.random() * 0.02 + 0.005;
                this.size = Math.random() * 3 + 1;
                this.color = {
                    r: Math.random() * 100 + 155,
                    g: Math.random() * 100 + 155,
                    b: Math.random() * 100 + 155
                };
            }
            
            update() {
                this.x += this.vx;
                this.y += this.vy;
                this.life -= this.decay;
                this.size *= 0.99;
            }
            
            draw() {
                ctx.save();
                ctx.globalAlpha = this.life;
                
                // 创建发光效果
                const gradient = ctx.createRadialGradient(
                    this.x, this.y, 0,
                    this.x, this.y, this.size * 3
                );
                gradient.addColorStop(0, `rgba(${this.color.r}, ${this.color.g}, ${this.color.b}, 1)`);
                gradient.addColorStop(0.5, `rgba(${this.color.r}, ${this.color.g}, ${this.color.b}, 0.5)`);
                gradient.addColorStop(1, `rgba(${this.color.r}, ${this.color.g}, ${this.color.b}, 0)`);
                
                ctx.fillStyle = gradient;
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.size * 3, 0, Math.PI * 2);
                ctx.fill();
                
                // 绘制核心粒子
                ctx.fillStyle = `rgba(${this.color.r}, ${this.color.g}, ${this.color.b}, 1)`;
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                ctx.fill();
                
                ctx.restore();
            }
        }
        
        // 五角星类
        class Star {
            constructor(x, y, size) {
                this.x = x;
                this.y = y;
                this.size = size;
                this.rotation = 0;
                this.glowIntensity = 0;
                this.glowDirection = 1;
                this.particles = [];
                this.lastParticleTime = 0;
            }
            
            // 计算五角星的顶点
            getStarPoints() {
                const points = [];
                const outerRadius = this.size;
                const innerRadius = this.size * 0.4;
                
                for (let i = 0; i < 10; i++) {
                    const angle = (i * Math.PI) / 5 + this.rotation;
                    const radius = i % 2 === 0 ? outerRadius : innerRadius;
                    const x = this.x + Math.cos(angle) * radius;
                    const y = this.y + Math.sin(angle) * radius;
                    points.push({ x, y });
                }
                
                return points;
            }
            
            update() {
                this.rotation += 0.01;
                
                // 更新发光强度
                this.glowIntensity += this.glowDirection * 0.02;
                if (this.glowIntensity >= 1 || this.glowIntensity <= 0) {
                    this.glowDirection *= -1;
                }
                
                // 生成粒子
                const now = Date.now();
                if (now - this.lastParticleTime > 50) {
                    this.generateParticles();
                    this.lastParticleTime = now;
                }
                
                // 更新粒子
                this.particles = this.particles.filter(particle => {
                    particle.update();
                    return particle.life > 0;
                });
            }
            
            generateParticles() {
                const points = this.getStarPoints();
                
                // 在五角星边缘生成粒子
                for (let i = 0; i < points.length; i++) {
                    const point = points[i];
                    const nextPoint = points[(i + 1) % points.length];
                    
                    // 在边缘随机位置生成粒子
                    const t = Math.random();
                    const x = point.x + (nextPoint.x - point.x) * t;
                    const y = point.y + (nextPoint.y - point.y) * t;
                    
                    if (Math.random() < 0.3) {
                        this.particles.push(new Particle(x, y));
                    }
                }
                
                // 在五角星顶点生成更多粒子
                for (let i = 0; i < points.length; i += 2) {
                    const point = points[i];
                    if (Math.random() < 0.5) {
                        this.particles.push(new Particle(point.x, point.y));
                    }
                }
            }
            
            draw() {
                const points = this.getStarPoints();
                
                // 绘制发光效果
                ctx.save();
                ctx.shadowColor = `rgba(255, 255, 100, ${this.glowIntensity})`;
                ctx.shadowBlur = 20 + this.glowIntensity * 30;
                
                // 绘制五角星主体
                ctx.fillStyle = `rgba(255, 255, 150, ${0.8 + this.glowIntensity * 0.2})`;
                ctx.strokeStyle = `rgba(255, 255, 200, ${0.9 + this.glowIntensity * 0.1})`;
                ctx.lineWidth = 2;
                
                ctx.beginPath();
                ctx.moveTo(points[0].x, points[0].y);
                for (let i = 1; i < points.length; i++) {
                    ctx.lineTo(points[i].x, points[i].y);
                }
                ctx.closePath();
                ctx.fill();
                ctx.stroke();
                
                ctx.restore();
                
                // 绘制粒子
                this.particles.forEach(particle => particle.draw());
            }
        }
        
        // 创建多个五角星
        const stars = [];
        const numStars = 3;
        
        for (let i = 0; i < numStars; i++) {
            const x = canvas.width / 4 + (i * canvas.width / 4);
            const y = canvas.height / 2 + Math.sin(i * 2) * 100;
            const size = 50 + Math.random() * 30;
            stars.push(new Star(x, y, size));
        }
        
        // 动画循环
        function animate() {
            // 清除画布
            ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            
            // 更新和绘制所有五角星
            stars.forEach(star => {
                star.update();
                star.draw();
            });
            
            requestAnimationFrame(animate);
        }
        
        // 窗口大小调整
        window.addEventListener('resize', () => {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
            
            // 重新定位五角星
            stars.forEach((star, i) => {
                star.x = canvas.width / 4 + (i * canvas.width / 4);
                star.y = canvas.height / 2 + Math.sin(i * 2) * 100;
            });
        });
        
        // 鼠标交互
        canvas.addEventListener('mousemove', (e) => {
            const rect = canvas.getBoundingClientRect();
            const mouseX = e.clientX - rect.left;
            const mouseY = e.clientY - rect.top;
            
            stars.forEach(star => {
                const dx = mouseX - star.x;
                const dy = mouseY - star.y;
                const distance = Math.sqrt(dx * dx + dy * dy);
                
                if (distance < 150) {
                    // 鼠标靠近时增加粒子生成
                    for (let i = 0; i < 3; i++) {
                        const angle = Math.random() * Math.PI * 2;
                        const radius = Math.random() * star.size;
                        const x = star.x + Math.cos(angle) * radius;
                        const y = star.y + Math.sin(angle) * radius;
                        star.particles.push(new Particle(x, y));
                    }
                }
            });
        });
        
        // 开始动画
        animate();
    </script>
</body>
</html>

如果你觉得这个效果有趣,不妨尝试修改参数,创造属于你自己的独特效果!