特性:婚礼结成弹窗触发全员双倍礼花特效,粉金配色浪漫爆炸,持续12秒
This commit is contained in:
@@ -80,6 +80,12 @@ const EffectManager = (() => {
|
|||||||
FireworksEffect.start(canvas, _cleanup);
|
FireworksEffect.start(canvas, _cleanup);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "wedding-fireworks":
|
||||||
|
// 婚礼专属:双倍礼花,粉金浪漫配色,持续 12 秒
|
||||||
|
if (typeof FireworksEffect !== "undefined") {
|
||||||
|
FireworksEffect.startDouble(canvas, _cleanup);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "rain":
|
case "rain":
|
||||||
if (typeof RainEffect !== "undefined") {
|
if (typeof RainEffect !== "undefined") {
|
||||||
RainEffect.start(canvas, _cleanup);
|
RainEffect.start(canvas, _cleanup);
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ const FireworksEffect = (() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 启动烟花特效
|
* 启动烟花特效(普通版)
|
||||||
*
|
*
|
||||||
* @param {HTMLCanvasElement} canvas 全屏 Canvas
|
* @param {HTMLCanvasElement} canvas 全屏 Canvas
|
||||||
* @param {Function} onEnd 特效结束回调
|
* @param {Function} onEnd 特效结束回调
|
||||||
@@ -251,7 +251,6 @@ const FireworksEffect = (() => {
|
|||||||
let launchCnt = 0;
|
let launchCnt = 0;
|
||||||
const MAX_LAUNCHES = 12;
|
const MAX_LAUNCHES = 12;
|
||||||
|
|
||||||
// 定时发射火箭
|
|
||||||
const launchInterval = setInterval(() => {
|
const launchInterval = setInterval(() => {
|
||||||
if (launchCnt >= MAX_LAUNCHES) {
|
if (launchCnt >= MAX_LAUNCHES) {
|
||||||
clearInterval(launchInterval);
|
clearInterval(launchInterval);
|
||||||
@@ -261,8 +260,7 @@ const FireworksEffect = (() => {
|
|||||||
const ty = h * (0.08 + Math.random() * 0.45);
|
const ty = h * (0.08 + Math.random() * 0.45);
|
||||||
const color = COLORS[Math.floor(Math.random() * COLORS.length)];
|
const color = COLORS[Math.floor(Math.random() * COLORS.length)];
|
||||||
const type = TYPES[Math.floor(Math.random() * TYPES.length)];
|
const type = TYPES[Math.floor(Math.random() * TYPES.length)];
|
||||||
const rocket = new Rocket(x, ty, color, type, h); // 传入画布高度
|
rockets.push(new Rocket(x, ty, color, type, h));
|
||||||
rockets.push(rocket);
|
|
||||||
launchCnt++;
|
launchCnt++;
|
||||||
}, 600);
|
}, 600);
|
||||||
|
|
||||||
@@ -271,11 +269,9 @@ const FireworksEffect = (() => {
|
|||||||
function animate(now) {
|
function animate(now) {
|
||||||
ctx.clearRect(0, 0, w, h);
|
ctx.clearRect(0, 0, w, h);
|
||||||
|
|
||||||
// 更新和绘制火箭
|
|
||||||
for (let i = rockets.length - 1; i >= 0; i--) {
|
for (let i = rockets.length - 1; i >= 0; i--) {
|
||||||
const r = rockets[i];
|
const r = rockets[i];
|
||||||
if (r.done) {
|
if (r.done) {
|
||||||
// 火箭爆炸:生成粒子
|
|
||||||
const burst = _burst(r.x, r.y, r.color, r.type);
|
const burst = _burst(r.x, r.y, r.color, r.type);
|
||||||
particles = particles.concat(burst);
|
particles = particles.concat(burst);
|
||||||
rockets.splice(i, 1);
|
rockets.splice(i, 1);
|
||||||
@@ -285,7 +281,6 @@ const FireworksEffect = (() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新和绘制粒子
|
|
||||||
particles = particles.filter((p) => p.alive);
|
particles = particles.filter((p) => p.alive);
|
||||||
particles.forEach((p) => {
|
particles.forEach((p) => {
|
||||||
p.update();
|
p.update();
|
||||||
@@ -305,5 +300,116 @@ const FireworksEffect = (() => {
|
|||||||
animId = requestAnimationFrame(animate);
|
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;
|
const me = window.chatContext.username;
|
||||||
this.isNewlywed = (groomName === me || brideName === me);
|
this.isNewlywed = (groomName === me || brideName === me);
|
||||||
this.show = true;
|
this.show = true;
|
||||||
// 播放烟花特效
|
// 播放婚礼专属双倍礼花特效(全员)
|
||||||
if (window.EffectManager) {
|
if (window.EffectManager) {
|
||||||
window.EffectManager.play('fireworks');
|
window.EffectManager.play('wedding-fireworks');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user