Skip to content

Commit

Permalink
完善代码细节
Browse files Browse the repository at this point in the history
  • Loading branch information
XXYoLoong committed Feb 9, 2024
1 parent db72045 commit 7f48f03
Show file tree
Hide file tree
Showing 4 changed files with 210 additions and 161 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"liveServer.settings.port": 5501
}
9 changes: 7 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="header">
<div id="additional-info">chayunyolong</div>
</div>
<div id="countdown">距离新年还有:00:00:00</div>
<button id="previewButton">预览烟花效果</button>
<canvas id="fireworksCanvas"></canvas>
<div id="greetings" style="display: none;">新年快乐!</div>
<div id="footer">
<a href="https://github.com/YoLongChayun/new-year-countdown.git">跳转至 GitHub</a>
</div>
<script src="script.js"></script>
</body>
</html>
</html>
285 changes: 153 additions & 132 deletions script.js
Original file line number Diff line number Diff line change
@@ -1,178 +1,199 @@
// 定义粒子类
// 粒子类定义
class Particle {
constructor(x, y, color, velocity) {
this.x = x;
this.y = y;
this.color = color;
this.velocity = velocity;
this.alpha = 1;
this.friction = 0.99;
this.gravity = 0.05;
// 粒子构造函数
constructor(x, y, radius, color, velocity, decay, gravity) {
this.x = x; // 粒子的x坐标
this.y = y; // 粒子的y坐标
this.radius = radius; // 粒子的半径
this.color = color; // 粒子的颜色
this.velocity = velocity; // 粒子的速度对象,包含x和y方向的速度
this.decay = decay || 0.015; // 粒子的衰减速率,默认值为0.015
this.alpha = 1; // 粒子的透明度,初始值为1
this.gravity = gravity || 0.05; // 粒子受到的重力加速度,默认值为0.05
}

// 绘制粒子的方法
draw() {
ctx.save();
ctx.globalAlpha = this.alpha;
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.arc(this.x, this.y, 3, 0, Math.PI * 2, false);
ctx.fill();
ctx.restore();
ctx.save(); // 保存当前绘图状态
ctx.globalAlpha = this.alpha; // 设置绘图透明度
ctx.beginPath(); // 开始绘制
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false); // 绘制圆形粒子
ctx.fillStyle = this.color; // 设置填充颜色
ctx.fill(); // 填充颜色
ctx.restore(); // 恢复之前保存的绘图状态
}

// 更新粒子状态的方法
update() {
this.velocity.x *= this.friction;
this.velocity.y *= this.friction;
this.velocity.y += this.gravity;
this.x += this.velocity.x;
this.y += this.velocity.y;
this.alpha -= 0.01;

if (this.alpha > 0) {
this.draw();
this.velocity.y += this.gravity; // 应用重力,使粒子下降
this.x += this.velocity.x; // 更新粒子的x坐标
this.y += this.velocity.y; // 更新粒子的y坐标
this.alpha -= this.decay; // 更新粒子的透明度
if (this.alpha <= this.decay) {
this.alpha = 0; // 当透明度小于衰减速率时,将透明度设置为0
}
this.draw(); // 绘制更新后的粒子
}
// 判断粒子是否仍然存活(透明度大于0)
isAlive() {
return this.alpha > 0;
}
}

// 定义烟花类
// 烟花类定义
class Firework {
constructor(x, y, targetY, color) {
this.x = x;
this.y = y;
this.targetY = targetY;
this.color = color;
this.velocity = { x: (Math.random() - 0.5) * 3, y: Math.random() * -3 - 4 };
this.particles = [];
this.exploded = false;
}

draw() {
if (!this.exploded) {
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.arc(this.x, this.y, 4, 0, Math.PI * 2, false);
ctx.fill();
}
// 烟花构造函数
constructor(x, y, color, riseSpeed = -1, particleSize = 2) {
this.x = x; // 烟花的x坐标
this.y = y; // 烟花的y坐标
this.color = color; // 烟花的颜色
this.riseSpeed = riseSpeed; // 烟花上升速度
this.particleSize = particleSize; // 爆炸后生成的粒子大小
this.particles = []; // 存储爆炸后生成的粒子数组
this.exploded = false; // 标记烟花是否已经爆炸
this.velocity = { x: Math.random() * 2 - 1, y: this.riseSpeed }; // 烟花的速度,x轴速度模拟风
}

explode() {
const effectType = Math.floor(Math.random() * 4); // 随机选择0到3之间的效果类型
const particleCount = 100; // 每种效果的粒子数量

for (let i = 0; i < particleCount; i++) {
let velocity;
switch (effectType) {
case 0: // 标准圆形爆炸
const angle = Math.random() * Math.PI * 2;
const speed = Math.random() * 6 + 1;
velocity = { x: Math.cos(angle) * speed, y: Math.sin(angle) * speed };
break;
case 1: // 心形爆炸
const angleHeart = Math.PI * i / (particleCount / 2);
const speedHeart = Math.sin(angleHeart) * 12;
velocity = { x: 16 * Math.pow(Math.sin(angleHeart), 3), y: -13 * Math.cos(angleHeart) + 5 * Math.cos(2 * angleHeart) - 2 * Math.cos(3 * angleHeart) - Math.cos(4 * angleHeart) };
break;
case 2: // 螺旋形爆炸
const angleSpiral = 0.1 * i;
const speedSpiral = 0.2 * i;
velocity = { x: Math.cos(angleSpiral) * speedSpiral, y: Math.sin(angleSpiral) * speedSpiral };
break;
case 3: // 随机散射爆炸
velocity = { x: (Math.random() - 0.5) * 12, y: (Math.random() - 0.5) * 12 };
break;
default: // 默认为标准圆形爆炸
const defaultAngle = Math.random() * Math.PI * 2;
const defaultSpeed = Math.random() * 6 + 1;
velocity = { x: Math.cos(defaultAngle) * defaultSpeed, y: Math.sin(defaultAngle) * defaultSpeed };
}
this.particles.push(new Particle(this.x, this.y, this.color, velocity));
}
// 烟花爆炸方法
explode() {
const pattern = Math.floor(Math.random() * 5); // 随机选择爆炸图案类型
const particleCount = 100 + Math.random() * 1000; // 确定爆炸生成的粒子数量
for (let i = 0; i < particleCount; i++) {
let speed, angle;
// 根据图案类型生成粒子速度和角度
switch(pattern) {
case 0: // 圆形
speed = Math.random() * 5 + 2; // 粒子速度
angle = Math.PI * 2 * i / particleCount; // 角度
break;
case 1: // 星星
speed = Math.random() * 5 + 2; // 粒子速度
angle = Math.PI * 2 * i / particleCount + Math.PI / 5; // 角度
break;
case 2: // 爱心
speed = Math.random() * 3 + 1; // 粒子速度
angle = Math.PI * 2 * i / particleCount; // 角度
break;
case 3: // 散射
speed = Math.random() * 5 + 2; // 粒子速度
angle = Math.PI * 2 * i / particleCount + Math.random() * Math.PI / 2 - Math.PI / 4; // 角度
break;
case 4: // 螺旋
speed = Math.random() * 5 + 2; // 粒子速度
angle = Math.PI * 2 * i / particleCount + Math.PI * 5 / 4 * Math.sin(Math.PI * 2 * i / particleCount); // 角度
break;
default:
speed = Math.random() * 5 + 2; // 粒子速度
angle = Math.PI * 2 * i / particleCount; // 默认角度
}

const decay = Math.random() * 0.04 + 0.01; // 粒子衰减速率
const gravity = Math.random() * 0.05 + 0.03; // 粒子重力加速度
// 创建新粒子并添加到粒子数组中
this.particles.push(new Particle(this.x, this.y, this.particleSize, `hsl(${Math.random() * 360}, 100%, 50%)`, {
x: Math.cos(angle) * speed,
y: Math.sin(angle) * speed
}, decay, gravity));
}
}

// 更新烟花状态的方法
update() {
if (!this.exploded) {
this.velocity.y += 0.1; // gravity
this.x += this.velocity.x;
this.y += this.velocity.y;

if (this.y >= this.targetY) {
this.exploded = true;
this.explode();
this.y += this.velocity.y; // 更新烟花的y坐标,使其上升
this.x += this.velocity.x; // 更新烟花的x坐标,模拟风效果
this.draw(); // 绘制上升中的烟花
// 判断烟花是否达到爆炸高度
if (this.y < canvas.height * (0.18 + Math.random() * 0.22)) {
this.exploded = true; // 标记烟花为已爆炸
this.explode(); // 触发烟花爆炸
}
this.draw();
} else {
this.particles.forEach((particle, index) => {
particle.update();
if (particle.alpha <= 0) {
this.particles.splice(index, 1);
}
});
// 更新所有粒子的状态,并移除已经“死亡”的粒子
this.particles = this.particles.filter(p => p.isAlive());
this.particles.forEach(p => p.update());
}
}
// 绘制上升中的烟花方法
draw() {
ctx.save(); // 保存当前绘图状态
ctx.globalAlpha = 1; // 设置绘图透明度为不透明
ctx.beginPath(); // 开始绘制
ctx.arc(this.x, this.y, 2, 0, Math.PI * 2, false); // 绘制表示烟花的小圆点
ctx.fillStyle = this.color; // 设置填充颜色
ctx.fill(); // 填充颜色
ctx.restore(); // 恢复之前保存的绘图状态
}
}

// 获取canvas元素并设置其宽高
const canvas = document.getElementById('fireworksCanvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

let fireworks = [];
let timerId;

let fireworks = []; // 存储所有烟花的数组
// 动画循环函数,用于不断更新画布上的内容
function animate() {
requestAnimationFrame(animate);
ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
ctx.fillRect(0, 0, canvas.width, canvas.height);

requestAnimationFrame(animate); // 请求下一帧动画
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'; // 设置画布覆盖颜色(用于创建尾迹效果)
ctx.fillRect(0, 0, canvas.width, canvas.height); // 覆盖整个画布
// 遍历所有烟花,更新它们的状态,并在必要时将它们从数组中移除
fireworks.forEach((firework, index) => {
firework.update();
if (firework.exploded && firework.particles.length === 0) {
fireworks.splice(index, 1);
fireworks.splice(index, 1); // 移除已经爆炸且粒子消失的烟花
}
});
}

function startFireworks() {
timerId = setInterval(() => {
const x = Math.random() * canvas.width;
const y = canvas.height + 10;
const targetY = canvas.height * (Math.random() * 0.5 + 0.1);
const color = `hsl(${Math.random() * 360}, 100%, 50%)`;
fireworks.push(new Firework(x, y, targetY, color));
}, 400);
// 创建新烟花的函数,用于在画布上添加新的烟花
function createFirework() {
const x = Math.random() * canvas.width; // 在画布宽度范围内随机选择x坐标
const y = canvas.height; // y坐标设置为画布底部
const color = `hsl(${Math.random() * 360}, 100%, 50%)`; // 随机选择颜色
const riseSpeed = -Math.random() * 8 + 1; // 随机生成上升速度
const particleSize = Math.random() * 3 + 2; // 随机生成粒子大小
// 创建新的烟花并添加到烟花数组中
fireworks.push(new Firework(x, y, color, riseSpeed, particleSize));
}
function launchFireworks() {
const initialFireworks = 30; // 第一次触发时的烟花数量
// 立即生成初始数量的烟花粒子
for (let i = 0; i < initialFireworks; i++) {
createFirework();
}
// 定时生成新的烟花粒子
const interval = setInterval(() => {
createFirework();
// 可以在这里添加逻辑来停止生成新的烟花粒子,例如设置一个生成烟花的总数限制
}, 200); // 每隔1秒生成一个新的烟花粒子
}

document.getElementById('previewButton').addEventListener('click', startFireworks);
// 触发烟花效果的函数,用于在特定条件下(如倒计时结束)启动一系列烟花
function triggerFireworks() {
const fireworksCount = 5; // 定义触发的烟花数量
for (let i = 0; i < fireworksCount; i++) {
// 每隔一秒触发一个烟花,创建连续的烟花效果
setTimeout(createFirework, i * 1000);
}
}

// 获取页面上的倒计时元素
// 倒计时逻辑,假设倒计时结束后触发烟花
const countdownElement = document.getElementById('countdown');
// 设置目标日期为2024年2月9日23:59:59
const targetDate = new Date('2024-02-09T23:59:59').getTime();
const targetDate = new Date('Feb 9, 2024 23:59:59').getTime();

// 倒计时更新函数
// 倒计时更新函数,用于显示距离目标日期的时间并在到达时触发烟花
function updateCountdown() {
const now = new Date().getTime(); // 获取当前时间戳
const distance = targetDate - now; // 计算当前时间与目标时间的差值

const now = new Date().getTime(); // 获取当前时间
const distance = targetDate - now; // 计算距离目标日期的时间差
// 计算天、小时、分钟和秒
const days = Math.floor(distance / (1000 * 60 * 60 * 24));
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((distance % (1000 * 60)) / 1000);

// 更新倒计时显示
countdownElement.innerHTML = `距离新年还有:${days}${hours}小时 ${minutes}${seconds}秒`;

// 检查倒计时是否结束
countdownElement.innerHTML = `距离新年还有:${days}${hours}小时${minutes}${seconds}秒`;
// 如果时间差小于0,说明目标日期已到达
if (distance < 0) {
clearInterval(timerId); // 停止倒计时
countdownElement.innerHTML = "新年快乐!"; // 显示新年快乐的信息
startFireworks(); // 触发烟花效果
clearInterval(interval); // 停止倒计时更新
countdownElement.style.display = 'none'; // 隐藏倒计时显示
document.getElementById('greetings').style.display = 'block'; // 显示新年祝福信息
launchFireworks(); // 使用 launchFireworks 函数触发烟花效果
}
}
const interval = setInterval(updateCountdown, 1000); // 每秒更新倒计时

// 使用setInterval每秒更新倒计时
timerId = setInterval(updateCountdown, 1000);

animate();
animate(); // 开始动画循环
Loading

0 comments on commit 7f48f03

Please sign in to comment.