slop game oder so
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Pausenmenü (Esc) mit Lautstärkereglern. Als HTML-Overlay umgesetzt, damit die
|
||||
* Schieberegler per Maus, Tastatur und Screenreader bedienbar sind.
|
||||
* @module scenes/PauseScene
|
||||
*/
|
||||
|
||||
import { ORBITAL } from '../config.js';
|
||||
import { formatSequence } from '../logic/format.js';
|
||||
import { PAUSE } from '../content/texts.js';
|
||||
import { oncePerEvent } from '../systems/keyboard.js';
|
||||
import { el, Overlay } from '../systems/Overlay.js';
|
||||
import { VOLUME_CHANNELS } from '../systems/Settings.js';
|
||||
|
||||
export class PauseScene extends Phaser.Scene {
|
||||
constructor() {
|
||||
super('Pause');
|
||||
}
|
||||
|
||||
create() {
|
||||
const { width, height } = this.scale;
|
||||
const services = this.registry.get('services');
|
||||
this.input.setDefaultCursor('default');
|
||||
// Solange die Pause offen ist, soll der Browser Tasten normal verarbeiten
|
||||
// (Pfeiltasten für Schieberegler, Tab für den Fokus).
|
||||
this.input.keyboard.disableGlobalCapture();
|
||||
services.audio.duck(true);
|
||||
this.add.rectangle(0, 0, width, height, 0x000000, 0.45).setOrigin(0);
|
||||
|
||||
const content = [el('p', 'disclaimer__lead', PAUSE.subtitle)];
|
||||
for (const channel of VOLUME_CHANNELS) {
|
||||
content.push(this.volumeField(channel, services.settings));
|
||||
}
|
||||
const codes = el('p', 'field__hint');
|
||||
codes.textContent = ORBITAL.commands
|
||||
.map((c) => `${c.shortName}: ${formatSequence(c.sequence)}`)
|
||||
.join(' · ');
|
||||
content.push(codes);
|
||||
|
||||
let quitArmed = false;
|
||||
this.overlay = new Overlay({
|
||||
id: 'pause-overlay',
|
||||
title: PAUSE.title,
|
||||
content,
|
||||
buttons: [
|
||||
{ label: PAUSE.resume, onClick: () => this.resume(), testId: 'pause-resume' },
|
||||
{
|
||||
label: PAUSE.quit,
|
||||
secondary: true,
|
||||
testId: 'pause-quit',
|
||||
onClick: () => {
|
||||
// Zweistufig statt Browser-Dialog: erster Klick fragt nach, zweiter bricht ab.
|
||||
if (!quitArmed) {
|
||||
quitArmed = true;
|
||||
quitButton.textContent = PAUSE.confirmQuit;
|
||||
return;
|
||||
}
|
||||
this.quit();
|
||||
},
|
||||
},
|
||||
],
|
||||
onEscape: () => this.resume(),
|
||||
});
|
||||
const quitButton = this.overlay.actions.lastElementChild;
|
||||
|
||||
this.input.keyboard.on(
|
||||
'keydown-ESC',
|
||||
oncePerEvent((event) => {
|
||||
if (!event.repeat) this.resume();
|
||||
}),
|
||||
);
|
||||
this.events.once('shutdown', () => {
|
||||
services.audio.duck(false);
|
||||
if (this.overlay.element.isConnected) this.overlay.close();
|
||||
this.input.keyboard?.enableGlobalCapture();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Schieberegler für einen Lautstärkekanal.
|
||||
* @param {'master'|'music'|'sfx'} channel
|
||||
* @param {import('../systems/Settings.js').Settings} settings
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
volumeField(channel, settings) {
|
||||
const field = el('label', 'field');
|
||||
const label = el('span', 'field__label', PAUSE.volumes[channel]);
|
||||
const input = /** @type {HTMLInputElement} */ (el('input', 'field__input'));
|
||||
input.type = 'range';
|
||||
input.min = '0';
|
||||
input.max = '100';
|
||||
input.step = '5';
|
||||
input.value = String(Math.round(settings.getVolume(channel) * 100));
|
||||
input.dataset.testid = `volume-${channel}`;
|
||||
input.addEventListener('input', () => settings.setVolume(channel, Number(input.value) / 100));
|
||||
field.append(label, input);
|
||||
return field;
|
||||
}
|
||||
|
||||
resume() {
|
||||
this.scene.resume('Game');
|
||||
this.scene.get('Game').input.setDefaultCursor('none');
|
||||
this.scene.stop();
|
||||
}
|
||||
|
||||
quit() {
|
||||
this.scene.stop('Hud');
|
||||
this.scene.stop('Game');
|
||||
this.scene.start('Menu');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user