JSDM

HTML

 
1
<!DOCTYPE html>
You don't need a DOCTYPE on CodePen. Just put here what you would normally put in the <body>.
2
<html>
3
<head>
4
    <title>中心扩散流星群</title>
5
    <style>
6
        body { margin: 0; overflow: hidden; background: #000; }
7
        canvas { display: block; }
8
    </style>
9
</head>
10
<body>
11
    <canvas id="canvas"></canvas>
12
    <script>
13
        const canvas = document.getElementById('canvas');
14
        const ctx = canvas.getContext('2d');
15
        canvas.width = window.innerWidth;
16
        canvas.height = window.innerHeight;
17
18
        class Meteor {
19
            constructor() {
20
                this.reset(true);
21
                this.hue = Math.random() * 360; // 随机色相值[6](@ref)
22
            }
23
24
            reset(initial) {
25
                this.x = canvas.width/2;
26
                this.y = canvas.height/2;
27
                this.angle = Math.random() * Math.PI * 2; // 360度随机方向[6](@ref)
28
                this.speed = Math.random() * 5 + 2; // 随机速度
29
                this.size = Math.random() * 2 + 1; // 随机大小
30
                this.alpha = 1;
31
                this.trail = [];
32
                this.trailLength = Math.floor(Math.random() * 15 + 10); // 随机尾迹长度
33
            }
34
35
            update() {
36
                // 添加位置到轨迹数组
37
                this.trail.push({x: this.x, y: this.y})
38
                if(this.trail.length > this.trailLength) this.trail.shift()
39
40
                // 计算新位置
41
                this.x += Math.cos(this.angle) * this.speed;
42
                this.y += Math.sin(this.angle) * this.speed;
43
                this.alpha -= 0.005;
44
45
                // 重置条件(出界或透明度耗尽)
46
                if(this.x < 0 || this.x > canvas.width || 
47
                   this.y < 0 || this.y > canvas.height ||
48
                   this.alpha <= 0) {
49
                    this.reset();
50
                }
51
            }
52
53
            draw() {
54
                // 绘制尾迹
55
                ctx.globalAlpha = this.alpha;
56
                this.trail.forEach((pos, index) => {
57
                    const ratio = index/this.trailLength;
58
                    ctx.beginPath();
59
                    ctx.arc(pos.x, pos.y, this.size * ratio, 0, Math.PI*2);
60
                    ctx.fillStyle = `hsla(${this.hue}, 100%, 50%, ${ratio*0.8})`;
61
                    ctx.fill();
62
                });
63
64
                // 绘制头部
65
                ctx.beginPath();
66
                ctx.arc(this.x, this.y, this.size, 0, Math.PI*2);
67
                ctx.fillStyle = `hsla(${this.hue}, 100%, 70%, ${this.alpha})`;
68
                ctx.fill();
69
            }
70
        }
71
72
        // 创建流星数组
73
        const meteors = Array(150).fill().map(() => new Meteor());
74
75
        function animate() {
76
            // 创建拖尾效果
77
            ctx.fillStyle = 'rgba(0, 0, 0, 0.05)';
78
            ctx.fillRect(0, 0, canvas.width, canvas.height);
79
80
            meteors.forEach(meteor => {
81
                meteor.update();
82
                meteor.draw();
83
            });
84
85
            requestAnimationFrame(animate);
86
        }
87
88
        // 窗口尺寸变化时重置
89
        window.addEventListener('resize', () => {
90
            canvas.width = window.innerWidth;
91
            canvas.height = window.innerHeight;
92
            meteors.forEach(meteor => meteor.reset(true));
93
        });
94
95
        animate();
96
    </script>
97
</body>
98
</html>
!

CSS

xxxxxxxxxx
1
 
1
? ?
? ?
必须是有效的URL
+ 添加另一个资源

JS

xxxxxxxxxx
68
 
1
const canvas = document.getElementById('starrySky');
2
const ctx = canvas.getContext('2d');
3
 
4
// 设置canvas尺寸以填充整个视口
5
canvas.width = window.innerWidth;
6
canvas.height = window.innerHeight;
7
 
8
// 粒子数组
9
const particles = [];
10
const numParticles = 150; // 粒子数量
11
const maxRadius = 5; // 最大半径
12
const minRadius = 2; // 最小半径
13
const speedFactor = 0.5; // 速度因子,控制粒子移动速度
14
 
15
// 创建粒子类
16
class Particle {
17
    constructor(x, y, radius, color) {
18
        this.x = x;
19
        this.y = y;
20
        this.radius = radius;
21
        this.color = color;
22
        this.speedX = Math.random() * speedFactor - speedFactor / 2; // 随机x轴速度
23
        this.speedY = Math.random() * speedFactor - speedFactor / 2; // 随机y轴速度
24
    }
25
 
26
    draw() {
27
        ctx.beginPath();
28
        ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
29
        ctx.fillStyle = this.color;
30
        ctx.fill();
31
    }
32
 
33
    update() {
34
        this.x += this.speedX;
35
        this.y += this.speedY;
36
        if (this.x + this.radius > canvas.width || this.x - this.radius < 0) {
37
            this.speedX *= -1; // 碰到边缘反弹
38
        }
39
        if (this.y + this.radius > canvas.height || this.y - this.radius < 0) {
40
            this.speedY *= -1; // 碰到边缘反弹
41
        }
42
    }
43
}
44
 
45
// 初始化粒子数组
46
function initParticles() {
47
    for (let i = 0; i < numParticles; i++) {
48
        const x = Math.random() * canvas.width;
49
        const y = Math.random() * canvas.height;
50
        const radius = Math.random() * (maxRadius - minRadius) + minRadius; // 随机半径大小
51
        const color = `rgba(${Math.random() * 255}, ${Math.random() * 255}, ${Math.random() * 255}, ${Math.random()})`; // 随机颜色和透明度
52
        particles.push(new Particle(x, y, radius, color));
53
    }
54
}
55
 
56
// 动画循环函数
57
function animate() {
58
    ctx.clearRect(0, 0, canvas.width, canvas.height); // 清除画布,重新绘制粒子
59
    particles.forEach(particle => {
60
        particle.update(); // 更新粒子位置和速度
61
        particle.draw(); // 绘制粒子到画布上
62
    });
63
    requestAnimationFrame(animate); // 请求下一帧动画,实现平滑动画效果
64
}
65
 
66
// 初始化并开始动画循环
67
initParticles();
68
animate();
必须是有效的URL
+ 添加另一个资源
Close

文件管理 点击文件查看URL

图片

  1. 暂无文件

CSS

  1. 暂无文件

JavaScript

  1. 暂无文件

其他

  1. 暂无文件
拖动文件到上面的区域或者:
加载中 ..................