特性:婚礼结成弹窗触发全员双倍礼花特效,粉金配色浪漫爆炸,持续12秒
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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 };
|
||||
})();
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user