特性:婚礼结成弹窗触发全员双倍礼花特效,粉金配色浪漫爆炸,持续12秒

This commit is contained in:
2026-03-01 18:35:08 +08:00
parent 1e5d11929e
commit 87d91db1ee
3 changed files with 122 additions and 10 deletions

View File

@@ -80,6 +80,12 @@ const EffectManager = (() => {
FireworksEffect.start(canvas, _cleanup);
}
break;
case "wedding-fireworks":
// 婚礼专属:双倍礼花,粉金浪漫配色,持续 12 秒
if (typeof FireworksEffect !== "undefined") {
FireworksEffect.startDouble(canvas, _cleanup);
}
break;
case "rain":
if (typeof RainEffect !== "undefined") {
RainEffect.start(canvas, _cleanup);

View File

@@ -234,7 +234,7 @@ const FireworksEffect = (() => {
}
/**
* 启动烟花特效
* 启动烟花特效(普通版)
*
* @param {HTMLCanvasElement} canvas 全屏 Canvas
* @param {Function} onEnd 特效结束回调
@@ -251,7 +251,6 @@ const FireworksEffect = (() => {
let launchCnt = 0;
const MAX_LAUNCHES = 12;
// 定时发射火箭
const launchInterval = setInterval(() => {
if (launchCnt >= MAX_LAUNCHES) {
clearInterval(launchInterval);
@@ -261,8 +260,7 @@ const FireworksEffect = (() => {
const ty = h * (0.08 + Math.random() * 0.45);
const color = COLORS[Math.floor(Math.random() * COLORS.length)];
const type = TYPES[Math.floor(Math.random() * TYPES.length)];
const rocket = new Rocket(x, ty, color, type, h); // 传入画布高度
rockets.push(rocket);
rockets.push(new Rocket(x, ty, color, type, h));
launchCnt++;
}, 600);
@@ -271,11 +269,9 @@ const FireworksEffect = (() => {
function animate(now) {
ctx.clearRect(0, 0, w, h);
// 更新和绘制火箭
for (let i = rockets.length - 1; i >= 0; i--) {
const r = rockets[i];
if (r.done) {
// 火箭爆炸:生成粒子
const burst = _burst(r.x, r.y, r.color, r.type);
particles = particles.concat(burst);
rockets.splice(i, 1);
@@ -285,7 +281,6 @@ const FireworksEffect = (() => {
}
}
// 更新和绘制粒子
particles = particles.filter((p) => p.alive);
particles.forEach((p) => {
p.update();
@@ -305,5 +300,116 @@ const FireworksEffect = (() => {
animId = requestAnimationFrame(animate);
}
return { start };
/**
* 启动婚礼加倍烟花特效(双侧轮流发射,粒子增倍,持续更久)
*
* @param {HTMLCanvasElement} canvas 全屏 Canvas
* @param {Function} onEnd 特效结束回调
*/
function startDouble(canvas, onEnd) {
const ctx = canvas.getContext("2d");
const w = canvas.width;
const h = canvas.height;
const DURATION = 12000; // 比普通多 2 秒
let rockets = [];
let particles = [];
let animId = null;
let launchCnt = 0;
const MAX_LAUNCHES = 24; // 双倍火箭数
// 婚礼专属浪漫色组(增加金色/粉色)
const WEDDING_COLORS = [
"#ff2266",
"#ff66aa",
"#ff99cc", // 粉红系
"#ffcc00",
"#ffdd44",
"#fff066", // 金黄系
"#cc44ff",
"#ff44cc",
"#aa00ff", // 紫色系
"#ff4400",
"#ff8800",
"#00ddff", // 其他
];
// 定时从左右两侧交替发射
const launchInterval = setInterval(() => {
if (launchCnt >= MAX_LAUNCHES) {
clearInterval(launchInterval);
return;
}
// 左右交替偶数从左侧1/3奇数从右侧2/3
const isLeft = launchCnt % 2 === 0;
const x = isLeft
? w * (0.05 + Math.random() * 0.4)
: w * (0.55 + Math.random() * 0.4);
const ty = h * (0.05 + Math.random() * 0.4);
const color =
WEDDING_COLORS[
Math.floor(Math.random() * WEDDING_COLORS.length)
];
const type = TYPES[Math.floor(Math.random() * TYPES.length)];
rockets.push(new Rocket(x, ty, color, type, h));
launchCnt++;
}, 400); // 发射间隔缩短到 400ms密度加倍
// 额外开场同时发射3枚双侧礼炮
setTimeout(() => {
[0.15, 0.5, 0.85].forEach((xRatio) => {
const color =
WEDDING_COLORS[
Math.floor(Math.random() * WEDDING_COLORS.length)
];
rockets.push(
new Rocket(w * xRatio, h * 0.1, color, "sphere", h),
);
});
}, 100);
const startTime = performance.now();
function animate(now) {
ctx.clearRect(0, 0, w, h);
for (let i = rockets.length - 1; i >= 0; i--) {
const r = rockets[i];
if (r.done) {
// 婚礼爆炸粒子数×1.5(在 _burst 基础上额外补充50粒
const burst = _burst(r.x, r.y, r.color, r.type);
// 额外补充粒子(心形/大颗)
for (let j = 0; j < 50; j++) {
const p = new Particle(r.x, r.y, r.color, "sphere", 0);
p.radius = Math.random() * 3 + 1;
burst.push(p);
}
particles = particles.concat(burst);
rockets.splice(i, 1);
} else {
r.update();
r.draw(ctx);
}
}
particles = particles.filter((p) => p.alive);
particles.forEach((p) => {
p.update();
p.draw(ctx);
});
if (now - startTime < DURATION) {
animId = requestAnimationFrame(animate);
} else {
clearInterval(launchInterval);
cancelAnimationFrame(animId);
ctx.clearRect(0, 0, w, h);
onEnd();
}
}
animId = requestAnimationFrame(animate);
}
return { start, startDouble };
})();

View File

@@ -673,9 +673,9 @@
const me = window.chatContext.username;
this.isNewlywed = (groomName === me || brideName === me);
this.show = true;
// 播放烟花特效
// 播放婚礼专属双倍礼花特效(全员)
if (window.EffectManager) {
window.EffectManager.play('fireworks');
window.EffectManager.play('wedding-fireworks');
}
},