186 lines
5.5 KiB
JavaScript
186 lines
5.5 KiB
JavaScript
export class MatchBanner {
|
||
play(scene, label, onComplete) {
|
||
const cx = 800;
|
||
const cy = 450;
|
||
|
||
// Dark overlay behind everything
|
||
const overlay = scene.add.graphics();
|
||
overlay.fillStyle(0x000000, 0.65);
|
||
overlay.fillRect(0, 0, 1600, 900);
|
||
overlay.setAlpha(0).setDepth(10);
|
||
|
||
// Expanding burst ring from center
|
||
const burst = scene.add.graphics();
|
||
burst.lineStyle(10, 0xffd700, 1);
|
||
burst.strokeCircle(0, 0, 50);
|
||
burst.setPosition(cx, cy).setDepth(11);
|
||
|
||
scene.tweens.add({
|
||
targets: burst,
|
||
scaleX: 18, scaleY: 18,
|
||
alpha: 0,
|
||
duration: 650,
|
||
ease: 'Cubic.easeOut',
|
||
onComplete: () => burst.destroy()
|
||
});
|
||
|
||
// Main banner container — starts tiny, punches in
|
||
const container = scene.add.container(cx, cy).setScale(0.01).setDepth(12);
|
||
|
||
const PW = 1060, PH = 260, PR = 22;
|
||
|
||
// Panel background
|
||
const panel = scene.add.graphics();
|
||
panel.fillStyle(0x0d0520, 0.97);
|
||
panel.fillRoundedRect(-PW / 2, -PH / 2, PW, PH, PR);
|
||
// Sharp gold inner border
|
||
panel.lineStyle(5, 0xffd700, 1);
|
||
panel.strokeRoundedRect(-PW / 2, -PH / 2, PW, PH, PR);
|
||
// Soft outer glow border
|
||
panel.lineStyle(16, 0xffd700, 0.18);
|
||
panel.strokeRoundedRect(-PW / 2 - 9, -PH / 2 - 9, PW + 18, PH + 18, PR + 9);
|
||
|
||
// Horizontal copper divider
|
||
const divider = scene.add.graphics();
|
||
divider.lineStyle(2, 0xc8a87e, 0.55);
|
||
divider.beginPath();
|
||
divider.moveTo(-430, -8);
|
||
divider.lineTo(430, -8);
|
||
divider.strokePath();
|
||
|
||
// Corner cross ornaments
|
||
const cornerPositions = [
|
||
[-PW / 2 + 30, -PH / 2 + 24],
|
||
[ PW / 2 - 30, -PH / 2 + 24],
|
||
[-PW / 2 + 30, PH / 2 - 24],
|
||
[ PW / 2 - 30, PH / 2 - 24],
|
||
];
|
||
const cornerCrosses = cornerPositions.map(([ox, oy]) =>
|
||
scene.add.text(ox, oy, '✝', {
|
||
fontSize: '22px',
|
||
fontFamily: 'Georgia, serif',
|
||
color: '#c8a87e',
|
||
}).setOrigin(0.5, 0.5).setAlpha(0.65)
|
||
);
|
||
|
||
// "M A T C H" header
|
||
const matchTxt = scene.add.text(0, -72, 'M A T C H', {
|
||
fontSize: '36px',
|
||
fontFamily: 'Georgia, serif',
|
||
color: '#c8a87e',
|
||
stroke: '#2a0a00',
|
||
strokeThickness: 2,
|
||
}).setOrigin(0.5, 0.5);
|
||
|
||
// "3× {LABEL}" main text
|
||
const mainTxt = scene.add.text(0, 58, `3\u00D7 ${label.toUpperCase()}`, {
|
||
fontSize: '88px',
|
||
fontFamily: 'Georgia, serif',
|
||
color: '#ffd700',
|
||
stroke: '#2a0a00',
|
||
strokeThickness: 7,
|
||
shadow: { offsetX: 0, offsetY: 0, color: '#ffd700', blur: 28, fill: true },
|
||
}).setOrigin(0.5, 0.5);
|
||
|
||
container.add([panel, divider, ...cornerCrosses, matchTxt, mainTxt]);
|
||
|
||
// Sparkle particles burst outward
|
||
for (let i = 0; i < 30; i++) {
|
||
const angle = (i / 30) * Math.PI * 2 + Phaser.Math.FloatBetween(-0.15, 0.15);
|
||
const dist = Phaser.Math.Between(100, 420);
|
||
const size = Phaser.Math.Between(16, 48);
|
||
const glyph = ['✦', '★', '✝', '✦', '★'][Math.floor(Math.random() * 5)];
|
||
|
||
const sparkle = scene.add.text(
|
||
cx + Math.cos(angle) * 15,
|
||
cy + Math.sin(angle) * 15,
|
||
glyph,
|
||
{ fontSize: `${size}px`, fontFamily: 'Georgia, serif', color: '#ffd700' }
|
||
).setOrigin(0.5, 0.5).setAlpha(0).setDepth(13);
|
||
|
||
scene.tweens.add({
|
||
targets: sparkle,
|
||
x: cx + Math.cos(angle) * dist,
|
||
y: cy + Math.sin(angle) * dist,
|
||
alpha: { from: 0, to: 1 },
|
||
scale: { from: 0.1, to: 1 },
|
||
duration: Phaser.Math.Between(280, 650),
|
||
delay: Phaser.Math.Between(40, 320),
|
||
ease: 'Cubic.easeOut',
|
||
onComplete: () => {
|
||
scene.tweens.add({
|
||
targets: sparkle,
|
||
alpha: 0,
|
||
scale: 0.4,
|
||
duration: Phaser.Math.Between(350, 800),
|
||
delay: Phaser.Math.Between(150, 500),
|
||
ease: 'Cubic.easeIn',
|
||
onComplete: () => sparkle.destroy(),
|
||
});
|
||
},
|
||
});
|
||
}
|
||
|
||
// Fade in overlay
|
||
scene.tweens.add({
|
||
targets: overlay,
|
||
alpha: 1,
|
||
duration: 140,
|
||
});
|
||
|
||
// Punch in the banner with elastic overshoot
|
||
scene.tweens.add({
|
||
targets: container,
|
||
scale: 1,
|
||
duration: 520,
|
||
ease: 'Back.easeOut',
|
||
easeParams: [4],
|
||
onComplete: () => {
|
||
// Scale pulse ×3
|
||
scene.tweens.add({
|
||
targets: container,
|
||
scale: 1.035,
|
||
duration: 200,
|
||
yoyo: true,
|
||
repeat: 2,
|
||
ease: 'Sine.easeInOut',
|
||
onComplete: () => {
|
||
// Gold shimmer flicker on main text
|
||
scene.tweens.add({
|
||
targets: mainTxt,
|
||
alpha: 0.55,
|
||
duration: 90,
|
||
yoyo: true,
|
||
repeat: 4,
|
||
ease: 'Linear',
|
||
onComplete: () => {
|
||
// Hold, then zoom-fade out
|
||
scene.time.delayedCall(650, () => {
|
||
scene.tweens.add({
|
||
targets: container,
|
||
scale: 1.14,
|
||
alpha: 0,
|
||
duration: 420,
|
||
ease: 'Cubic.easeIn',
|
||
onComplete: () => container.destroy(),
|
||
});
|
||
scene.tweens.add({
|
||
targets: overlay,
|
||
alpha: 0,
|
||
duration: 420,
|
||
ease: 'Cubic.easeIn',
|
||
onComplete: () => {
|
||
overlay.destroy();
|
||
if (onComplete) onComplete();
|
||
},
|
||
});
|
||
});
|
||
},
|
||
});
|
||
},
|
||
});
|
||
},
|
||
});
|
||
}
|
||
}
|