<!DOCTYPE html> <html> <head> <title>渐显白色流星群</title> <style> body { margin: 0; overflow: hidden; background: #000; } canvas { display: block; } </style> </head> <body> <canvas id="canvas"></canvas> <script> const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; class Meteor { constructor() { this.reset(true); } reset() { this.x = canvas.width/2; this.y = canvas.height/2; this.angle = Math.random() * Math.PI * 2; this.speed = Math.random() * 1.2 + 0.3; // 更慢的速度范围 this.size = Math.random() * 2 + 1; this.trail = []; this.trailLength = Math.floor(Math.random() * 25 + 15); // 更长尾迹 this.maxDistance = Math.max(canvas.width, canvas.height) / 2; // 动态最大距离 } update() { // 记录轨迹点 this.trail.push({ x: this.x, y: this.y }) if(this.trail.length > this.trailLength) this.trail.shift() // 计算新位置 this.x += Math.cos(this.angle) * this.speed; this.y += Math.sin(this.angle) * this.speed; // 基于距离计算透明度 const dx = this.x - canvas.width/2; const dy = this.y - canvas.height/2; const distance = Math.sqrt(dx*dx + dy*dy); this.alpha = Math.min(distance / this.maxDistance, 1); // 距离渐显 // 重置条件(仅位置判断) if(this.x < 0 || this.x > canvas.width || this.y < 0 || this.y > canvas.height) { this.reset(); } } draw() { // 绘制尾迹 this.trail.forEach((pos, index) => { const ratio = index/this.trailLength; ctx.beginPath(); ctx.arc(pos.x, pos.y, this.size * ratio, 0, Math.PI*2); ctx.fillStyle = `rgba(255, 255, 255, ${ratio * 0.6 * this.alpha})`; // 复合透明度 ctx.fill(); }); // 绘制头部 ctx.beginPath(); ctx.arc(this.x, this.y, this.size, 0, Math.PI*2); ctx.fillStyle = `rgba(255, 255, 255, ${this.alpha})`; ctx.fill(); } } const meteors = Array(150).fill().map(() => new Meteor()); function animate() { ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'; // 更淡的尾迹残留 ctx.fillRect(0, 0, canvas.width, canvas.height); meteors.forEach(meteor => { meteor.update(); meteor.draw(); }); requestAnimationFrame(animate); } window.addEventListener('resize', () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight; meteors.forEach(meteor => meteor.reset()); }); animate(); </script> </body> </html>