mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:01:09 +02:00
Split monolithic RPGScene.js (1210 lines) into modular manager classes: - WorldManager, PlayerManager, NPCManager, ChatUI, StorageManager, SoundManager, TouchControls Key improvements: - Constants config (GAME_CONFIG) replacing all magic numbers - JSDoc types + jsconfig.json for IDE type-safety - LocalStorage persistence for progress, stats, and custom avatars - Synthesized sound effects via Web Audio API - 26 NPCs (up from 10) in 3 categories - Stats/leaderboard in main menu - Pixel editor avatar integration with RPG game - Mobile touch controls (virtual joystick + interact button) - Chat UI with typing indicator and conversation history - Interactive tutorial overlay for first-time players - Floating question mark over NPCs in range - Server hardened: rate limiting, input sanitization, CORS restrictions, API timeouts, conversation history cap - Particle effect object pooling - i18n framework with DE/EN and language switcher Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
130 lines
3.1 KiB
JavaScript
130 lines
3.1 KiB
JavaScript
class MainMenuScene extends Phaser.Scene {
|
|
constructor() {
|
|
super({ key: 'MainMenuScene' });
|
|
}
|
|
|
|
create() {
|
|
const { COLORS } = GAME_CONFIG;
|
|
const centerX = this.cameras.main.width / 2;
|
|
|
|
this.add.image(centerX, 300, 'background');
|
|
|
|
// Titel
|
|
this.add
|
|
.text(centerX, 100, I18N.t('title'), {
|
|
fontSize: '64px',
|
|
fill: COLORS.TEXT_WHITE,
|
|
fontStyle: 'bold',
|
|
})
|
|
.setOrigin(0.5);
|
|
|
|
this.add
|
|
.text(centerX, 160, I18N.t('subtitle'), {
|
|
fontSize: '32px',
|
|
fill: COLORS.TEXT_WHITE,
|
|
})
|
|
.setOrigin(0.5);
|
|
|
|
// Statistiken
|
|
this._showStats(centerX);
|
|
|
|
// Buttons
|
|
this._createButton(centerX, 300, I18N.t('startGame'), () => {
|
|
this.scene.start('RPGScene');
|
|
});
|
|
|
|
this._createButton(centerX, 370, I18N.t('pixelEditor'), () => {
|
|
this.scene.start('GameScene');
|
|
});
|
|
|
|
this._createButton(centerX, 440, I18N.t('resetProgress'), () => {
|
|
new StorageManager().reset();
|
|
this._showStats(centerX);
|
|
|
|
const confirmText = this.add
|
|
.text(centerX, 500, I18N.t('progressReset'), {
|
|
fontSize: '18px',
|
|
fill: COLORS.TEXT_REVEALED,
|
|
fontFamily: 'Arial',
|
|
})
|
|
.setOrigin(0.5);
|
|
|
|
this.tweens.add({
|
|
targets: confirmText,
|
|
alpha: 0,
|
|
duration: 1500,
|
|
delay: 1500,
|
|
onComplete: () => confirmText.destroy(),
|
|
});
|
|
});
|
|
|
|
// Sprach-Umschalter (rechts oben)
|
|
const langBtn = this.add
|
|
.text(this.cameras.main.width - 20, 20, I18N.getLanguage().toUpperCase(), {
|
|
fontSize: '20px',
|
|
fontFamily: 'Arial',
|
|
fontStyle: 'bold',
|
|
fill: COLORS.TEXT_WHITE,
|
|
backgroundColor: COLORS.BACK_BUTTON_BG,
|
|
padding: { x: 10, y: 5 },
|
|
})
|
|
.setOrigin(1, 0)
|
|
.setInteractive({ useHandCursor: true });
|
|
|
|
langBtn.on('pointerover', () => langBtn.setStyle({ fill: COLORS.BACK_BUTTON_HOVER }));
|
|
langBtn.on('pointerout', () => langBtn.setStyle({ fill: COLORS.TEXT_WHITE }));
|
|
langBtn.on('pointerdown', () => {
|
|
const newLang = I18N.toggle();
|
|
// Scene neu laden, um Texte zu aktualisieren
|
|
this.scene.restart();
|
|
});
|
|
}
|
|
|
|
_showStats(centerX) {
|
|
const { COLORS } = GAME_CONFIG;
|
|
const storage = new StorageManager();
|
|
const stats = storage.getStats();
|
|
|
|
if (this.statsText) this.statsText.destroy();
|
|
|
|
if (stats.totalRevealed > 0) {
|
|
this.statsText = this.add
|
|
.text(
|
|
centerX,
|
|
220,
|
|
[
|
|
`${I18N.t('statsRevealed')}: ${stats.totalRevealed}`,
|
|
`${I18N.t('statsAvgGuesses')}: ${stats.averageGuesses}`,
|
|
`${I18N.t('statsBestStreak')}: ${stats.bestStreak}`,
|
|
].join(' | '),
|
|
{
|
|
fontSize: '16px',
|
|
fontFamily: 'Arial',
|
|
fill: COLORS.TEXT_NPC_RESPONSE,
|
|
align: 'center',
|
|
}
|
|
)
|
|
.setOrigin(0.5);
|
|
}
|
|
}
|
|
|
|
_createButton(x, y, label, onClick) {
|
|
const { COLORS } = GAME_CONFIG;
|
|
|
|
const button = this.add
|
|
.text(x, y, label, {
|
|
fontSize: '28px',
|
|
fill: COLORS.TEXT_WHITE,
|
|
backgroundColor: COLORS.BACK_BUTTON_BG,
|
|
padding: { x: 20, y: 10 },
|
|
})
|
|
.setOrigin(0.5)
|
|
.setInteractive({ useHandCursor: true });
|
|
|
|
button.on('pointerover', () => button.setStyle({ fill: COLORS.BACK_BUTTON_HOVER }));
|
|
button.on('pointerout', () => button.setStyle({ fill: COLORS.TEXT_WHITE }));
|
|
button.on('pointerdown', onClick);
|
|
|
|
return button;
|
|
}
|
|
}
|