HTML实现流星雨
代码文件:「基于html实现流星+星辰」,链接:https://pan.quark.cn/s/59679c01ebc5
整体结构
该项目采用简洁的单文件结构,主要由三部分组成:
- HTML 结构:定义基础页面和 Canvas 元素
- CSS 样式:设置全屏黑色背景和 Canvas 布局
- JavaScript 逻辑:实现星星背景、流星生成和动画效果
核心功能实现
1. Canvas 初始化
const canvas = document.getElementById('meteorCanvas');
const ctx = canvas.getContext('2d');function resizeCanvas() {canvas.width = window.innerWidth;canvas.height = window.innerHeight;
}resizeCanvas();
window.addEventListener('resize', resizeCanvas);
这段代码首先获取 Canvas 元素及其 2D 渲染上下文,然后定义了 resizeCanvas()
函数来确保 Canvas 尺寸与窗口同步,并添加窗口大小改变事件监听器以实现响应式效果。
2. 星空背景实现
const stars = [];
const starCount = 500;function initStars() {stars.length = 0;for (let i = 0; i < starCount; i++) {stars.push({x: Math.random() * canvas.width,y: Math.random() * canvas.height,size: Math.random() * 2 + 0.5,opacity: Math.random() * 0.7 + 0.3,twinkleSpeed: Math.random() * 0.02 + 0.005,twinkleDirection: 1});}
}
初始化函数 initStars()
创建了 500 个随机分布的星星,每个星星都有独立的位置、大小、透明度和闪烁参数,为后续实现闪烁效果奠定基础。
3. 流星生成机制
const meteors = [];function createMeteor() {const angle = Math.PI / 4; // 45度角// 随机起始位置:左侧或上方let startX, startY;if (Math.random() > 0.5) {startX = Math.random() * -100;startY = Math.random() * canvas.height * 0.7;} else {startX = Math.random() * canvas.width * 0.7;startY = Math.random() * -100;}// 计算结束位置const flightDistance = Math.sqrt(canvas.width * canvas.width + canvas.height * canvas.height) * 1.5;const endX = startX + Math.cos(angle) * flightDistance;const endY = startY + Math.sin(angle) * flightDistance;// 流星属性meteors.push({x: startX,y: startY,endX: endX,endY: endY,length: Math.random() * 70 + 80,width: Math.random() * 1 + 1,speed: Math.random() * 10 + 5,progress: 0,alpha: 1,color: getRandomMeteorColor()});
}
流星生成函数是实现流星雨效果的核心。它通过以下机制工作:
- 设置固定的 45 度角,确保所有流星保持统一的飞行方向
- 随机选择起始位置(屏幕左侧或上方)
- 根据固定角度和飞行距离计算结束位置,确保流星能够完整划过屏幕
- 为每个流星设置随机的长度、宽度、速度等属性,增加视觉变化
4. 流星颜色系统
function getRandomMeteorColor() {const colors = ['rgba(255, 255, 255, ', // 纯白色'rgba(255, 248, 225, ', // 米白色'rgba(255, 250, 240, ', // 淡雪青色'rgba(255, 255, 240, ' // 象牙白];return colors[Math.floor(Math.random() * colors.length)];
}
该函数返回四种白亮色中的一种,确保流星在黑色背景上具有良好的可见性,同时保持流星雨的自然美感。
5. 渲染函数实现
5.1 星星渲染与闪烁效果
function drawStars() {ctx.fillStyle = 'white';stars.forEach(star => {// 实现星星闪烁效果star.opacity += star.twinkleSpeed * star.twinkleDirection;if (star.opacity > 1 || star.opacity < 0.3) {star.twinkleDirection *= -1;}ctx.globalAlpha = star.opacity;ctx.fillRect(star.x, star.y, star.size, star.size);});ctx.globalAlpha = 1;
}
drawStars()
函数不仅绘制星星,还实现了星星的闪烁效果。通过不断调整每个星星的透明度,并在达到阈值时反转变化方向,创造出星星忽明忽暗的动态效果。
5.2 流星渲染与轨迹效果
function drawMeteors() {meteors.forEach((meteor, index) => {// 更新流星位置meteor.progress += meteor.speed / (Math.sqrt(Math.pow(meteor.endX - meteor.x, 2) + Math.pow(meteor.endY - meteor.y, 2)));// 计算当前位置const currentX = meteor.x + (meteor.endX - meteor.x) * meteor.progress;const currentY = meteor.y + (meteor.endY - meteor.y) * meteor.progress;// 透明度随进度变化meteor.alpha = 1 - meteor.progress;ctx.globalAlpha = meteor.alpha;// 绘制流星轨迹const angle = Math.atan2(meteor.endY - meteor.y, meteor.endX - meteor.x);const trailX = currentX - Math.cos(angle) * meteor.length;const trailY = currentY - Math.sin(angle) * meteor.length;// 创建渐变效果const gradient = ctx.createLinearGradient(trailX, trailY, currentX, currentY);gradient.addColorStop(0, 'rgba(0, 0, 0, 0)');gradient.addColorStop(0.5, meteor.color + (meteor.alpha * 0.8) + ')');gradient.addColorStop(1, meteor.color + (meteor.alpha * 1.5) + ')');// 绘制流星主体ctx.strokeStyle = gradient;ctx.lineWidth = meteor.width;ctx.lineCap = 'round';ctx.beginPath();ctx.moveTo(trailX, trailY);ctx.lineTo(currentX, currentY);ctx.stroke();// 绘制流星头部光晕ctx.beginPath();ctx.arc(currentX, currentY, meteor.width * 2.5, 0, Math.PI * 2);ctx.fillStyle = meteor.color + (meteor.alpha * 1.0) + ')';ctx.fill();// 移除已完成的流星if (meteor.progress >= 1) {meteors.splice(index, 1);}});ctx.globalAlpha = 1;
}
drawMeteors()
函数是渲染逻辑中最复杂的部分,它实现了:
- 基于进度的位置更新算法
- 透明度随进度的自然衰减
- 使用线性渐变创建流星的轨迹效果
- 在流星头部添加光晕效果,增强视觉冲击力
- 自动移除已完成飞行的流星,避免内存泄漏
6. 动画循环与定时生成
function animate() {// 清空画布ctx.fillStyle = 'black';ctx.fillRect(0, 0, canvas.width, canvas.height);// 绘制星星drawStars();// 绘制流星drawMeteors();// 请求下一帧requestAnimationFrame(animate);
}function scheduleMeteors() {// 批量生成流星const meteorBatchCount = Math.floor(Math.random() * 4) + 3; // 3-6个/批for (let i = 0; i < meteorBatchCount; i++) {createMeteor();}// 设置随机间隔const next = Math.random() * 300 + 50; // 50-300毫秒setTimeout(scheduleMeteors, next);
}
animate()
函数使用requestAnimationFrame()
创建流畅的动画循环,每帧清空画布并重新渲染所有元素scheduleMeteors()
函数实现了流星雨的密集效果,每批生成 3-6 个流星,并在 50-300 毫秒的随机间隔后生成下一批
7. 程序初始化
// 初始化并启动动画
initStars();
scheduleMeteors();
animate();
最后,程序通过简单的三行代码启动:初始化星星背景、开始定时生成流星、启动动画循环。