<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);
this.hue = Math.random() * 360; // 随机色相值[6](@ref)
}
reset(initial) {
this.x = canvas.width/2;
this.y = canvas.height/2;
this.angle = Math.random() * Math.PI * 2; // 360度随机方向[6](@ref)
this.speed = Math.random() * 5 + 2; // 随机速度
this.size = Math.random() * 2 + 1; // 随机大小
this.alpha = 1;
this.trail = [];
this.trailLength = Math.floor(Math.random() * 15 + 10); // 随机尾迹长度
}
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;
this.alpha -= 0.005;
// 重置条件(出界或透明度耗尽)
if(this.x < 0 || this.x > canvas.width ||
this.y < 0 || this.y > canvas.height ||
this.alpha <= 0) {
this.reset();
}
}
draw() {
// 绘制尾迹
ctx.globalAlpha = this.alpha;
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 = `hsla(${this.hue}, 100%, 50%, ${ratio*0.8})`;
ctx.fill();
});
// 绘制头部
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI*2);
ctx.fillStyle = `hsla(${this.hue}, 100%, 70%, ${this.alpha})`;
ctx.fill();
}
}
// 创建流星数组
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 => meteor.reset(true));
});
animate();
</script>
</body>
</html>
xxxxxxxxxx
xxxxxxxxxx
const canvas = document.getElementById('starrySky');
const ctx = canvas.getContext('2d');
// 设置canvas尺寸以填充整个视口
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// 粒子数组
const particles = [];
const numParticles = 150; // 粒子数量
const maxRadius = 5; // 最大半径
const minRadius = 2; // 最小半径
const speedFactor = 0.5; // 速度因子,控制粒子移动速度
// 创建粒子类
class Particle {
constructor(x, y, radius, color) {
this.x = x;
this.y = y;
this.radius = radius;
this.color = color;
this.speedX = Math.random() * speedFactor - speedFactor / 2; // 随机x轴速度
this.speedY = Math.random() * speedFactor - speedFactor / 2; // 随机y轴速度
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
ctx.fillStyle = this.color;
ctx.fill();
}
update() {
this.x += this.speedX;
this.y += this.speedY;
if (this.x + this.radius > canvas.width || this.x - this.radius < 0) {
this.speedX *= -1; // 碰到边缘反弹
}
if (this.y + this.radius > canvas.height || this.y - this.radius < 0) {
this.speedY *= -1; // 碰到边缘反弹
}
}
}
// 初始化粒子数组
function initParticles() {
for (let i = 0; i < numParticles; i++) {
const x = Math.random() * canvas.width;
const y = Math.random() * canvas.height;
const radius = Math.random() * (maxRadius - minRadius) + minRadius; // 随机半径大小
const color = `rgba(${Math.random() * 255}, ${Math.random() * 255}, ${Math.random() * 255}, ${Math.random()})`; // 随机颜色和透明度
particles.push(new Particle(x, y, radius, color));
}
}
// 动画循环函数
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height); // 清除画布,重新绘制粒子
particles.forEach(particle => {
particle.update(); // 更新粒子位置和速度
particle.draw(); // 绘制粒子到画布上
});
requestAnimationFrame(animate); // 请求下一帧动画,实现平滑动画效果
}
// 初始化并开始动画循环
initParticles();
animate();