feat(SCOPONE-0010): improve capture pacing and settings
This commit is contained in:
193
src/scenes/SettingsScene.ts
Normal file
193
src/scenes/SettingsScene.ts
Normal file
@@ -0,0 +1,193 @@
|
||||
import Phaser from 'phaser';
|
||||
import {
|
||||
AudioPreferences,
|
||||
SettingsSceneData,
|
||||
loadAudioPreferences,
|
||||
saveAudioPreferences,
|
||||
} from '../game/preferences';
|
||||
|
||||
type ToggleDefinition = {
|
||||
key: keyof AudioPreferences;
|
||||
label: string;
|
||||
description: string;
|
||||
};
|
||||
|
||||
type ToggleVisuals = {
|
||||
background: Phaser.GameObjects.Rectangle;
|
||||
statusText: Phaser.GameObjects.Text;
|
||||
};
|
||||
|
||||
const TOGGLE_DEFINITIONS: ToggleDefinition[] = [
|
||||
{
|
||||
key: 'musicEnabled',
|
||||
label: 'Musica del tavolo',
|
||||
description: 'Controlla il tappeto sonoro di sottofondo durante la partita.',
|
||||
},
|
||||
{
|
||||
key: 'effectsEnabled',
|
||||
label: 'Effetti di gioco',
|
||||
description: 'Attiva prese, scope e segnali sonori senza toccare la musica.',
|
||||
},
|
||||
];
|
||||
|
||||
export class SettingsScene extends Phaser.Scene {
|
||||
private preferences: AudioPreferences = loadAudioPreferences();
|
||||
private returnSceneKey = 'MenuScene';
|
||||
private toggleVisuals = new Map<keyof AudioPreferences, ToggleVisuals>();
|
||||
|
||||
constructor() {
|
||||
super({ key: 'SettingsScene' });
|
||||
}
|
||||
|
||||
create(data?: SettingsSceneData): void {
|
||||
const width = this.scale.width;
|
||||
const height = this.scale.height;
|
||||
|
||||
this.preferences = loadAudioPreferences();
|
||||
this.returnSceneKey = data?.returnSceneKey ?? 'MenuScene';
|
||||
|
||||
this.add.rectangle(0, 0, width, height, 0x123d22).setOrigin(0);
|
||||
this.add.rectangle(width / 2, height / 2, width - 120, height - 120, 0x0d2216, 0.88)
|
||||
.setStrokeStyle(2, 0xd9b75f, 0.45);
|
||||
|
||||
this.add.text(width / 2, 120, 'Impostazioni audio', {
|
||||
fontFamily: 'Georgia, serif',
|
||||
fontSize: '46px',
|
||||
color: '#ffd700',
|
||||
stroke: '#000000',
|
||||
strokeThickness: 4,
|
||||
resolution: 2,
|
||||
}).setOrigin(0.5);
|
||||
|
||||
this.add.text(width / 2, 176, 'Musica ed effetti sono separati: ogni scelta viene salvata subito e sarà usata nelle prossime partite.', {
|
||||
fontFamily: 'Georgia, serif',
|
||||
fontSize: '19px',
|
||||
color: '#d7ead1',
|
||||
resolution: 2,
|
||||
align: 'center',
|
||||
wordWrap: { width: 760 },
|
||||
}).setOrigin(0.5);
|
||||
|
||||
TOGGLE_DEFINITIONS.forEach((definition, index) => {
|
||||
this.createToggleRow(definition, width / 2, 286 + index * 132, 760, 96);
|
||||
});
|
||||
|
||||
this.add.text(width / 2, 556, 'Puoi tornare al menu in qualsiasi momento: la difficoltà si sceglie lì, l’audio resta salvato qui.', {
|
||||
fontFamily: 'Georgia, serif',
|
||||
fontSize: '16px',
|
||||
color: '#cfe5cd',
|
||||
resolution: 2,
|
||||
align: 'center',
|
||||
wordWrap: { width: 720 },
|
||||
}).setOrigin(0.5);
|
||||
|
||||
this.createButton(width / 2, height - 112, 280, 60, 'Torna al menu', 'Rientra alla schermata iniziale', () => {
|
||||
this.returnToMenu();
|
||||
});
|
||||
}
|
||||
|
||||
private createToggleRow(definition: ToggleDefinition, x: number, y: number, width: number, height: number): void {
|
||||
const row = this.add.rectangle(x, y, width, height, 0x173323, 0.96)
|
||||
.setStrokeStyle(2, 0xcaa74a, 0.35)
|
||||
.setInteractive({ useHandCursor: true });
|
||||
|
||||
this.add.text(x - width / 2 + 28, y - 16, definition.label, {
|
||||
fontFamily: 'Georgia, serif',
|
||||
fontSize: '24px',
|
||||
color: '#ffffff',
|
||||
resolution: 2,
|
||||
}).setOrigin(0, 0.5);
|
||||
|
||||
this.add.text(x - width / 2 + 28, y + 14, definition.description, {
|
||||
fontFamily: 'Georgia, serif',
|
||||
fontSize: '16px',
|
||||
color: '#d8ead2',
|
||||
resolution: 2,
|
||||
wordWrap: { width: 470 },
|
||||
}).setOrigin(0, 0.5);
|
||||
|
||||
const toggleBackground = this.add.rectangle(x + width / 2 - 106, y, 148, 46, 0x356b39, 1)
|
||||
.setStrokeStyle(2, 0xf5e1a4, 0.45);
|
||||
const statusText = this.add.text(x + width / 2 - 106, y, '', {
|
||||
fontFamily: 'Georgia, serif',
|
||||
fontSize: '20px',
|
||||
color: '#ffffff',
|
||||
resolution: 2,
|
||||
}).setOrigin(0.5);
|
||||
|
||||
this.toggleVisuals.set(definition.key, {
|
||||
background: toggleBackground,
|
||||
statusText,
|
||||
});
|
||||
|
||||
row.on('pointerdown', () => {
|
||||
this.togglePreference(definition.key);
|
||||
});
|
||||
row.on('pointerover', () => row.setFillStyle(0x1d402c, 1));
|
||||
row.on('pointerout', () => row.setFillStyle(0x173323, 0.96));
|
||||
|
||||
this.refreshToggle(definition.key);
|
||||
}
|
||||
|
||||
private createButton(
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
height: number,
|
||||
label: string,
|
||||
subtitle: string,
|
||||
onClick: () => void,
|
||||
): void {
|
||||
const button = this.add.rectangle(x, y, width, height, 0x1f6f78, 1)
|
||||
.setStrokeStyle(2, 0xf5e1a4, 0.4)
|
||||
.setInteractive({ useHandCursor: true });
|
||||
|
||||
this.add.text(x, y - 10, label, {
|
||||
fontFamily: 'Georgia, serif',
|
||||
fontSize: '21px',
|
||||
color: '#ffffff',
|
||||
stroke: '#000000',
|
||||
strokeThickness: 2,
|
||||
resolution: 2,
|
||||
}).setOrigin(0.5);
|
||||
|
||||
this.add.text(x, y + 14, subtitle, {
|
||||
fontFamily: 'Georgia, serif',
|
||||
fontSize: '13px',
|
||||
color: '#f7f1d5',
|
||||
resolution: 2,
|
||||
align: 'center',
|
||||
}).setOrigin(0.5);
|
||||
|
||||
button.on('pointerover', () => button.setFillStyle(0x2f8f99));
|
||||
button.on('pointerout', () => button.setFillStyle(0x1f6f78));
|
||||
button.on('pointerdown', onClick);
|
||||
}
|
||||
|
||||
private togglePreference(key: keyof AudioPreferences): void {
|
||||
this.preferences = saveAudioPreferences({
|
||||
...this.preferences,
|
||||
[key]: !this.preferences[key],
|
||||
});
|
||||
this.refreshToggle(key);
|
||||
}
|
||||
|
||||
private refreshToggle(key: keyof AudioPreferences): void {
|
||||
const visuals = this.toggleVisuals.get(key);
|
||||
|
||||
if (!visuals) {
|
||||
return;
|
||||
}
|
||||
|
||||
const enabled = this.preferences[key];
|
||||
visuals.background.setFillStyle(enabled ? 0x356b39 : 0x7a2f2f);
|
||||
visuals.statusText.setText(enabled ? 'Attivo' : 'Disattivato');
|
||||
}
|
||||
|
||||
private returnToMenu(): void {
|
||||
this.cameras.main.fadeOut(250, 0, 30, 0);
|
||||
this.cameras.main.once('camerafadeoutcomplete', () => {
|
||||
this.scene.start(this.returnSceneKey);
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user