105 lines
3.3 KiB
JavaScript
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 });
|
|
}
|
|
}
|