import * as Phaser from 'phaser'; import { GAME_HEIGHT, GAME_WIDTH, COLORS } from '../config.js'; import { auth } from '../services/auth.js'; import { Button } from '../ui/Button.js'; import { addFullscreenButton } from '../ui/FullscreenButton.js'; import { playMenuMusic } from '../ui/MenuMusic.js'; export default class LandingScene extends Phaser.Scene { constructor() { super('Landing'); } create() { playMenuMusic(); const cx = GAME_WIDTH / 2; this.add.image(cx, GAME_HEIGHT / 2, 'bg-menu').setDisplaySize(GAME_WIDTH, GAME_HEIGHT); const logo = this.add.image(cx, 290, 'main-title').setOrigin(0.5, 0.5).setAlpha(0); logo.postFX.addShadow(3, 6, 0.005, 2, 0x000000, 10, 0.75); this.tweens.add({ targets: logo, alpha: 1, y: 260, duration: 900, ease: 'Power2', onComplete: () => { this.tweens.add({ targets: logo, scaleX: 1.025, scaleY: 1.025, duration: 2200, yoyo: true, repeat: -1, ease: 'Sine.easeInOut', }); }, }); this.renderButtons(); addFullscreenButton(this); if (this._authUnsub) this._authUnsub(); this._authUnsub = auth.subscribe(() => { if (!this.scene.isActive('Landing')) return; this.children.removeAll(); this.create(); }); this.events.once(Phaser.Scenes.Events.SHUTDOWN, () => { if (this._authUnsub) { this._authUnsub(); this._authUnsub = null; } }); } renderButtons() { const cx = GAME_WIDTH / 2; const user = auth.user; const avatarR = 28; const avatarGap = 18; const pad = { x: 32, y: 14 }; const y = 630; const name = user?.displayName ?? user?.username ?? 'Player'; const welcomeText = this.add.text(0, y, `Welcome, ${name}`, { fontFamily: 'Righteous', fontSize: '36px', color: COLORS.accentHex, }).setOrigin(0.5).setDepth(1); const hasAvatar = !!user?.avatarPath; const totalW = hasAvatar ? avatarR * 2 + avatarGap + welcomeText.width : welcomeText.width; const groupLeft = cx - totalW / 2; welcomeText.setX(hasAvatar ? groupLeft + avatarR * 2 + avatarGap + welcomeText.width / 2 : cx); this.add.rectangle(cx, y, totalW + pad.x * 2, welcomeText.height + pad.y * 2, 0x000000, 0.45); if (hasAvatar) { const avatarCx = groupLeft + avatarR; const key = `landing-avatar-${user.id}`; (async () => { try { if (!this.textures.exists(key)) { await new Promise((resolve) => { this.load.image(key, user.avatarPath); this.load.once('complete', resolve); this.load.start(); }); } if (!this.scene.isActive('Landing')) return; const maskG = this.make.graphics({ x: 0, y: 0, add: false }); maskG.fillStyle(0xffffff); maskG.fillCircle(avatarCx, y, avatarR); this.add.image(avatarCx, y, key) .setDisplaySize(avatarR * 2, avatarR * 2) .setMask(maskG.createGeometryMask()) .setDepth(1); } catch { /* no avatar shown */ } })(); } new Button(this, cx, 810, 'Play', () => this.scene.start('GameMenu'), { width: 480 }); new Button(this, cx, 890, 'Profile', () => this.scene.start('Profile'), { width: 480 }); } }