<!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.active = false; this.delay = Math.random() * 3000; // 初始随机延迟(0-3秒) this.trail = []; } reset() { this.x = canvas.width/2; this.y = canvas.height/2; this.angle = Math.random() * Math.PI * 2; this.speed = Math.random() * 3 + 1; this.size = Math.random() * 1 + 0.5; this.trailLength = 10 + Math.random() * 8; this.maxDistance = Math.hypot(canvas.width, canvas.height) * 1.2; this.active = true; } update() { if (!this.active) { this.delay -= 16; if (this.delay <= 0) this.reset(); return; } // 轨迹管理 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; this.alpha = Math.min(Math.hypot(dx, dy) / 80, 1); // 边界重置 if (Math.abs(dx) > this.maxDistance || Math.abs(dy) > this.maxDistance) { this.active = false; this.delay = 100 + Math.random() * 500; // 重生间隔0.1-0.6秒 this.trail = []; } } draw() { if (!this.active) return; // 绘制尾迹 this.trail.forEach((pos, i) => { const ratio = i / this.trailLength; ctx.beginPath(); ctx.arc(pos.x, pos.y, this.size * (1 - ratio) * 0.6, 0, Math.PI*2); ctx.fillStyle = `rgba(255,255,255,${(1 - ratio) * 0.3 * 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(); } } // 创建流星池(数量增加到150) const meteors = Array(150).fill().map(() => new Meteor()); function animate() { ctx.fillStyle = 'rgba(0, 0, 0, 0.05)'; 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 => { if (meteor.active) meteor.reset(); }); }); animate(); </script> </body> </html>