slop game oder so

This commit is contained in:
2026-09-24 17:57:54 +02:00
commit 4c997eee21
166 changed files with 14976 additions and 0 deletions
+93
View File
@@ -0,0 +1,93 @@
/**
* Senkrechte Menüliste aus Canvas-Texten, bedienbar mit Maus und Tastatur.
* @module ui/MenuList
*/
import { oncePerEvent } from '../systems/keyboard.js';
import { UI } from './theme.js';
/**
* @typedef {Object} MenuItem
* @property {string} label
* @property {() => void} onSelect
*/
export class MenuList {
/**
* @param {Phaser.Scene} scene
* @param {number} x Mittelpunkt
* @param {number} y Oberkante des ersten Eintrags
* @param {MenuItem[]} items
* @param {{spacing?: number, fontSize?: number}} [options]
*/
constructor(scene, x, y, items, options = {}) {
this.scene = scene;
this.items = items;
this.audio = scene.registry.get('services')?.audio ?? null;
this.index = 0;
this.enabled = true;
const spacing = options.spacing ?? 58;
const fontSize = options.fontSize ?? 30;
this.texts = items.map((item, i) => {
const text = scene.add
.text(x, y + i * spacing, item.label.toUpperCase(), {
...UI.text,
fontSize: `${fontSize}px`,
color: UI.colors.cream,
})
.setOrigin(0.5)
.setInteractive({ useHandCursor: true });
text.on('pointerover', () => {
if (this.enabled) this.focus(i);
});
text.on('pointerup', () => {
if (this.enabled) this.select(i);
});
return text;
});
this.keys = scene.input.keyboard.addKeys('UP,DOWN,W,S,ENTER,SPACE');
this.onKeyDown = oncePerEvent((event) => {
if (!this.enabled || event.repeat) return;
if (event.code === 'ArrowUp' || event.code === 'KeyW') this.focus(this.index - 1);
else if (event.code === 'ArrowDown' || event.code === 'KeyS') this.focus(this.index + 1);
else if (event.code === 'Enter' || event.code === 'Space' || event.code === 'NumpadEnter') this.select(this.index);
});
scene.input.keyboard.on('keydown', this.onKeyDown);
scene.events.once('shutdown', () => this.destroy());
this.focus(0);
}
/** @param {number} index */
focus(index) {
const count = this.items.length;
const next = (index + count) % count;
if (next !== this.index) this.audio?.play('ui-click');
this.index = next;
this.texts.forEach((text, i) => {
const active = i === this.index;
text.setColor(active ? UI.colors.gold : UI.colors.cream);
text.setScale(active ? 1.08 : 1);
// Großbuchstaben wie auf einem Plakat; die Texte selbst bleiben normal geschrieben.
const label = this.items[i].label.toUpperCase();
text.setText(active ? `» ${label} «` : label);
});
}
/** @param {number} index */
select(index) {
this.focus(index);
this.audio?.play('ui-confirm');
this.items[index].onSelect();
}
/** @param {boolean} enabled */
setEnabled(enabled) {
this.enabled = enabled;
}
destroy() {
this.scene.input.keyboard?.off('keydown', this.onKeyDown);
}
}
+53
View File
@@ -0,0 +1,53 @@
/**
* Gemeinsame Text- und Farbstile für Canvas-Texte (Menüs, HUD).
*
* Es werden bewusst nur Systemschriften verwendet: Nichts wird mitgeliefert, also
* gibt es keine Lizenzfragen, und die Buchstaben sind eindeutig lesbar (die
* Tastenhinweise „Q“, „X“ oder „K“ dürfen nicht wie „O“ oder „H“ aussehen).
* @module ui/theme
*/
export const UI = Object.freeze({
/** Plakatschrift für Titel und große Zahlen. */
titleFont: 'Impact, Haettenschweiler, "Arial Narrow Bold", "Arial Black", sans-serif',
/** Gut lesbare Schrift für HUD, Tabellen und Fließtext. */
uiFont: '"Segoe UI", system-ui, -apple-system, Roboto, "Helvetica Neue", Arial, sans-serif',
/** Für Pfeile und Symbole. */
symbolFont: '"Segoe UI Symbol", "Segoe UI", system-ui, sans-serif',
colors: Object.freeze({
gold: '#f2c14e',
cream: '#f4ecd8',
crimson: '#c1121f',
muted: '#a9b1c4',
navy: '#0d1321',
danger: '#ff6b5a',
ok: '#5ad469',
cyan: '#9be7ff',
}),
/** Standard-Textstil (Titelschrift) mit dunkler Kontur für Lesbarkeit auf jedem Hintergrund. */
text: Object.freeze({
fontFamily: 'Impact, Haettenschweiler, "Arial Narrow Bold", "Arial Black", sans-serif',
fontSize: '20px',
color: '#f4ecd8',
stroke: '#0d1321',
strokeThickness: 4,
}),
});
/**
* Titelschrift-Stil mit Änderungen.
* @param {Partial<Phaser.Types.GameObjects.Text.TextStyle>} overrides
* @returns {Phaser.Types.GameObjects.Text.TextStyle}
*/
export function textStyle(overrides = {}) {
return { ...UI.text, ...overrides };
}
/**
* Wie {@link textStyle}, aber in der gut lesbaren, fetten UI-Schrift (HUD, Tabellen, Fließtext).
* @param {Partial<Phaser.Types.GameObjects.Text.TextStyle>} overrides
* @returns {Phaser.Types.GameObjects.Text.TextStyle}
*/
export function uiStyle(overrides = {}) {
return { ...UI.text, fontFamily: UI.uiFont, fontStyle: 'bold', ...overrides };
}