mafia / frontend /src /scenes /_TemplateCharacterSelect.ts
Alfaxad's picture
Migrate Mafia game to ZeroGPU Gradio Space
c670567 verified
Raw
History Blame Contribute Delete
7.67 kB
/**
* ============================================================================
* TEMPLATE: Character Selection Scene
* ============================================================================
*
* INSTRUCTIONS FOR AGENT:
* 1. Copy this file and rename (e.g., HeroSelectScene.ts)
* 2. Rename the class and constructor scene key
* 3. Implement getSelectableCharacters() with your game's characters
* 4. Set getNextSceneKey() to your first game scene
* 5. Override hooks as needed for custom UI
*
* CRITICAL RULES:
* - This extends BaseCharacterSelectScene. All hooks are available.
* - Override getSelectableCharacters() (REQUIRED).
* - Override getNextSceneKey() to navigate to your battle/chapter scene.
* - For PVP (2 players pick sequentially):
* Override shouldAutoTransition() to return false.
* Track P1/P2 picks manually, then call triggerTransition().
*
* REGISTRY:
* - On confirm, base class stores: registry.set('selectedCharacter', character)
* - Retrieve in battle scene: this.registry.get('selectedCharacter')
* - For PVP, store per-player:
* this.registry.set('p1Character', character)
* this.registry.set('p2Character', character)
*
* TYPE IMPORTS:
* All interfaces/types MUST use the "type" keyword:
* import { BaseCharacterSelectScene, type SelectableCharacter } from './BaseCharacterSelectScene';
*
* FILE CHECKLIST (complete AFTER implementing this scene):
* [ ] main.ts — import and register this scene with game.scene.add()
* [ ] LevelManager.ts — add scene key to LEVEL_ORDER
* [ ] asset-pack.json — register ALL character portrait/expression texture keys
* [ ] gameConfig.json — merge characterSelectConfig values if customizing grid
* ============================================================================
*/
import {
BaseCharacterSelectScene,
type SelectableCharacter,
} from './BaseCharacterSelectScene';
export class _TemplateCharacterSelect extends BaseCharacterSelectScene {
constructor() {
super({ key: '_TemplateCharacterSelect' }); // TODO: Replace with your scene key
}
// ============================================================================
// REQUIRED: Define selectable characters
// ============================================================================
protected override getSelectableCharacters(): SelectableCharacter[] {
return [
// TODO: Define your characters
// {
// id: 'warrior',
// name: 'Warrior',
// description: 'A brave warrior with strong defense',
// imageKey: 'warrior_portrait', // Must match asset-pack.json key
// stats: { hp: 120, atk: 15, def: 25 },
// metadata: {
// expressions: {
// neutral: 'warrior_neutral',
// angry: 'warrior_angry',
// victory: 'warrior_victory',
// },
// },
// },
// {
// id: 'mage',
// name: 'Mage',
// description: 'Master of arcane spells',
// imageKey: 'mage_portrait',
// stats: { hp: 80, atk: 25, def: 10 },
// metadata: {
// expressions: {
// neutral: 'mage_neutral',
// angry: 'mage_angry',
// victory: 'mage_victory',
// },
// },
// },
];
}
// ============================================================================
// REQUIRED: Navigation
// ============================================================================
protected override getNextSceneKey(): string {
return 'ChapterSelectScene'; // TODO: Replace with your first game scene
}
// ============================================================================
// OPTIONAL: Scene setup hooks
// ============================================================================
protected override createBackground(): void {
const cam = this.cameras.main;
// TODO: Use your background image
// if (this.textures.exists('select_bg')) {
// const bg = this.add.image(cam.width / 2, cam.height / 2, 'select_bg');
// bg.setDisplaySize(cam.width, cam.height);
// } else {
this.add.rectangle(
cam.width / 2,
cam.height / 2,
cam.width,
cam.height,
0x1a1a2e,
);
// }
}
protected override createTitle(): void {
const cam = this.cameras.main;
// IMPORTANT: Assign to this.titleText so PVP mode can update it.
this.titleText = this.add
.text(cam.width / 2, 50, 'SELECT YOUR CHARACTER', {
fontSize: '36px',
fontFamily: 'Arial',
color: '#ffffff',
stroke: '#000000',
strokeThickness: 4,
fontStyle: 'bold',
})
.setOrigin(0.5);
}
protected override getBackgroundMusicKey(): string | undefined {
// TODO: Return audio key for background music
// return this.cache.audio.exists('select_bgm') ? 'select_bgm' : undefined;
return undefined;
}
protected override createCustomUI(): void {
// TODO: Add custom UI elements (decorations, instructions, etc.)
}
protected override onCharacterSelected(character: SelectableCharacter): void {
// Base class already stores: registry.set('selectedCharacter', character)
// Use 'selectedCharacter' to retrieve in battle scene:
// const char = this.registry.get('selectedCharacter');
// TODO: Play selection SFX
// if (this.cache.audio.exists('confirm_sfx')) {
// this.sound.play('confirm_sfx');
// }
}
// ============================================================================
// OPTIONAL: Grid customization
// ============================================================================
// protected override getGridConfig(): GridConfig {
// return {
// maxColumns: 5, // 5 columns instead of default 4
// cardWidth: 160, // Slightly narrower cards
// cardHeight: 220,
// gapX: 15,
// gapY: 15,
// };
// }
// ============================================================================
// OPTIONAL: Audio hooks
// ============================================================================
// protected override playSelectSound(): void {
// if (this.cache.audio.exists('ui_select')) {
// this.sound.play('ui_select', { volume: 0.3 });
// }
// }
// protected override playConfirmSound(): void {
// if (this.cache.audio.exists('ui_confirm')) {
// this.sound.play('ui_confirm', { volume: 0.5 });
// }
// }
// ============================================================================
// PVP SEQUENTIAL PICK PATTERN (optional)
// ============================================================================
// Uncomment for games where P1 and P2 each pick a character:
//
// private pickingPlayer: 'P1' | 'P2' = 'P1';
//
// protected override shouldAutoTransition(): boolean {
// return false; // We handle transition manually
// }
//
// protected override onCharacterSelected(character: SelectableCharacter): void {
// const pickedIndex = this.selectedIndex; // Save before reset
// if (this.pickingPlayer === 'P1') {
// this.registry.set('p1Character', character);
// this.pickingPlayer = 'P2';
// // Gray out P1's card, reset highlight to first available card
// this.resetForNextPick(pickedIndex);
// // Update title for P2
// if (this.titleText) {
// this.titleText.setText('PLAYER 2: SELECT CHARACTER');
// }
// } else {
// this.registry.set('p2Character', character);
// this.triggerTransition(); // Both players picked, go to battle
// }
// }
}