slop game oder so
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* Hauptmenü mit Propaganda-Laufband. Beim allerersten Start wird zuerst der
|
||||
* Disclaimer angezeigt; das Menü ist erst danach bedienbar.
|
||||
* @module scenes/MenuScene
|
||||
*/
|
||||
|
||||
import { GAME } from '../config.js';
|
||||
import { MENU, PROPAGANDA, TAGLINE, TITLE } from '../content/texts.js';
|
||||
import { TEXTURE_KEYS } from '../systems/Placeholders.js';
|
||||
import { MenuList } from '../ui/MenuList.js';
|
||||
import { textStyle, UI, uiStyle } from '../ui/theme.js';
|
||||
|
||||
/** Geschwindigkeit des Laufbands in px/s. */
|
||||
const TICKER_SPEED = 90;
|
||||
/** Anzahl Scheinwerferkegel im Hintergrund. */
|
||||
const SEARCHLIGHTS = 3;
|
||||
|
||||
export class MenuScene extends Phaser.Scene {
|
||||
constructor() {
|
||||
super('Menu');
|
||||
}
|
||||
|
||||
create() {
|
||||
const { width, height } = this.scale;
|
||||
const services = this.registry.get('services');
|
||||
this.input.setDefaultCursor('default');
|
||||
|
||||
this.drawBackground(width, height);
|
||||
|
||||
this.add.image(width / 2, 150, TEXTURE_KEYS.emblem).setDisplaySize(150, 150);
|
||||
this.add
|
||||
.text(width / 2, 262, TITLE, textStyle({ fontSize: '68px', color: UI.colors.gold, strokeThickness: 10, stroke: '#7a0a12' }))
|
||||
.setOrigin(0.5);
|
||||
this.add.text(width / 2, 318, TAGLINE, textStyle({ fontSize: '24px' })).setOrigin(0.5);
|
||||
|
||||
this.menu = new MenuList(this, width / 2, 372, [
|
||||
{ label: MENU.start, onSelect: () => this.startMission() },
|
||||
{ label: MENU.highscores, onSelect: () => this.scene.start('Highscores') },
|
||||
{ label: MENU.controls, onSelect: () => this.scene.start('Controls') },
|
||||
{ label: MENU.disclaimer, onSelect: () => this.openDisclaimer(false) },
|
||||
{ label: MENU.credits, onSelect: () => this.scene.start('Credits') },
|
||||
], { spacing: 54 });
|
||||
|
||||
this.add.text(width / 2, height - 62, MENU.hint, uiStyle({ fontSize: '16px', color: UI.colors.muted })).setOrigin(0.5);
|
||||
this.createTicker(width, height);
|
||||
|
||||
// Reine Touch-Geräte (Handy, Tablet) haben weder WASD noch Maus – lieber gleich sagen.
|
||||
if (globalThis.matchMedia?.('(pointer: coarse)').matches && !globalThis.matchMedia?.('(any-pointer: fine)').matches) {
|
||||
this.add.text(width / 2, height - 92, MENU.touchNotice, uiStyle({ fontSize: '18px', color: UI.colors.danger })).setOrigin(0.5);
|
||||
}
|
||||
|
||||
// Ton darf erst nach einer Nutzeraktion starten (Browser-Richtlinie); die Musik
|
||||
// wird vorgemerkt und beginnt mit dem ersten Klick oder Tastendruck.
|
||||
services.audio.startMusic();
|
||||
this.input.once('pointerdown', () => services.audio.unlock());
|
||||
this.input.keyboard.once('keydown', () => services.audio.unlock());
|
||||
|
||||
if (!services.settings.isDisclaimerAccepted()) {
|
||||
this.openDisclaimer(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} mandatory Beim ersten Start muss bestätigt werden.
|
||||
*/
|
||||
openDisclaimer(mandatory) {
|
||||
this.menu.setEnabled(false);
|
||||
this.scene.launch('Disclaimer', { mandatory });
|
||||
this.scene.get('Disclaimer').events.once('disclaimer-closed', () => {
|
||||
this.menu.setEnabled(true);
|
||||
});
|
||||
}
|
||||
|
||||
startMission() {
|
||||
this.registry.get('services').audio.unlock();
|
||||
this.scene.start('Briefing');
|
||||
}
|
||||
|
||||
drawBackground(width, height) {
|
||||
const bg = this.add.graphics();
|
||||
bg.fillGradientStyle(0x0d1321, 0x0d1321, 0x2a0a10, 0x2a0a10, 1);
|
||||
bg.fillRect(0, 0, width, height);
|
||||
// Diagonale Streifen wie auf einem Propagandaplakat.
|
||||
bg.fillStyle(0xc1121f, 0.08);
|
||||
for (let x = -height; x < width; x += 90) {
|
||||
bg.fillTriangle(x, height, x + 45, height, x + height + 45, 0);
|
||||
}
|
||||
|
||||
for (let i = 0; i < SEARCHLIGHTS; i += 1) {
|
||||
const beam = this.add.triangle(width * (0.2 + 0.3 * i), height + 20, 0, 0, -120, -height * 1.1, 120, -height * 1.1, 0xf2c14e, 0.06);
|
||||
beam.setOrigin(0, 0);
|
||||
this.tweens.add({
|
||||
targets: beam,
|
||||
angle: { from: -25, to: 25 },
|
||||
duration: 4200 + i * 900,
|
||||
yoyo: true,
|
||||
repeat: -1,
|
||||
ease: 'Sine.easeInOut',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
createTicker(width, height) {
|
||||
const bar = this.add.rectangle(0, height - 36, width, 36, 0xc1121f, 0.9).setOrigin(0, 0);
|
||||
bar.setDepth(GAME.depth.hud);
|
||||
const line = PROPAGANDA.join(' ★ ');
|
||||
this.ticker = this.add
|
||||
.text(width, height - 18, line, uiStyle({ fontSize: '19px', strokeThickness: 0 }))
|
||||
.setOrigin(0, 0.5)
|
||||
.setDepth(GAME.depth.hud + 1);
|
||||
}
|
||||
|
||||
update(_time, delta) {
|
||||
if (!this.ticker) return;
|
||||
this.ticker.x -= (TICKER_SPEED * delta) / 1000;
|
||||
if (this.ticker.x < -this.ticker.width) this.ticker.x = this.scale.width;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user