fertig-classic-games/src/scenes/LandingScene.js

105 lines
3.3 KiB
JavaScript

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 });
}
}