Spaces:
Running on Zero
Running on Zero
| /** | |
| * ============================================================================ | |
| * TEMPLATE: Chapter Scene (Narrative/Dialogue) | |
| * ============================================================================ | |
| * | |
| * INSTRUCTIONS FOR AGENT: | |
| * 1. Copy this file and rename (e.g., Chapter1Scene.ts, IntroScene.ts) | |
| * 2. Rename the class | |
| * 3. Define dialogue content in initializeDialogues() | |
| * 4. Register characters in createCharacters() | |
| * 5. Override hooks as needed for custom behavior | |
| * | |
| * CRITICAL RULES: | |
| * - initializeDialogues() is REQUIRED - must return dialogue entries | |
| * - Use registerCharacter() in createCharacters() for each character | |
| * - Do NOT override create() - base class handles the full lifecycle | |
| * - Background/music keys must match asset-pack.json | |
| * - All interface/type imports MUST use "type" keyword | |
| * - Config access: import gameConfig from '../gameConfig.json'; | |
| * const gameplayConfig = gameConfig.gameplayConfig ?? {}; | |
| * then use gameplayConfig.textSpeed.value (use .value accessor) | |
| * | |
| * DEFAULT BEHAVIOR (provided by base class, can be overridden): | |
| * - createDialogueUI(): Creates DialogueBox + ChoicePanel | |
| * - setupDefaultInputs(): Click/Enter/Space to advance dialogue | |
| * - showDialogueText(): Shows text in DialogueBox with typewriter effect | |
| * - showChoiceUI(): Shows choice buttons via ChoicePanel | |
| * - handleCharacterEnter(): Creates CharacterPortrait with slide-in animation | |
| * - handleCharacterExit(): Slides CharacterPortrait out | |
| * - handleDialogueInput(): Delegates to DialogueBox for skip/advance | |
| * - getDialogueBoxConfig(): Returns style config for default DialogueBox | |
| * | |
| * CUSTOMIZATION: | |
| * - To change dialogue box appearance: override getDialogueBoxConfig() | |
| * - To use speech bubbles instead: override createDialogueUI() + showDialogueText() | |
| * - To use a custom choice UI: override showChoiceUI(), call resolveChoice(index) | |
| * - To change input scheme: override setupDefaultInputs() | |
| * - To change character display: override handleCharacterEnter/Exit() | |
| * | |
| * FILE CHECKLIST (complete AFTER implementing this scene): | |
| * [ ] main.ts — import { YourScene } from './scenes/YourScene'; | |
| * [ ] main.ts — game.scene.add("YourSceneKey", YourScene); | |
| * [ ] LevelManager.ts — add "YourSceneKey" to LEVEL_ORDER | |
| * [ ] asset-pack.json — all texture/audio keys used here must be registered | |
| * [ ] gameConfig.json — merge custom gameplay values (keep screenSize/debugConfig) | |
| * [ ] TitleScreen.ts — update game title text | |
| * ============================================================================ | |
| */ | |
| import Phaser from 'phaser'; | |
| import { | |
| BaseChapterScene, | |
| type DialogueEntry, | |
| type ChoiceOption, | |
| } from './BaseChapterScene'; | |
| export class _TemplateChapter extends BaseChapterScene { | |
| constructor() { | |
| super({ key: '_TemplateChapter' }); // TODO: Replace with your scene key | |
| } | |
| // ============================================================================ | |
| // REQUIRED: Define dialogue content | |
| // ============================================================================ | |
| protected override initializeDialogues(): DialogueEntry[] { | |
| return [ | |
| // -- Scene opening -- | |
| // { type: 'text', speaker: 'narrator', text: 'The story begins...' }, | |
| // -- Character enters -- | |
| // { type: 'character', action: 'enter', characterId: 'hero', position: 'left' }, | |
| // -- Character dialogue with expression -- | |
| // { type: 'text', speaker: 'hero', text: 'Hello, world!', expression: 'happy' }, | |
| // -- Player choice -- | |
| // { type: 'choice', id: 'greeting', prompt: 'How do you respond?', options: [ | |
| // { text: 'Wave back', effects: { friendship: +1 } }, | |
| // { text: 'Ignore them', effects: { friendship: -1 } }, | |
| // ]}, | |
| // -- Special event (screen shake, sound, etc.) -- | |
| // { type: 'event', action: 'screen_shake', data: { intensity: 0.02 } }, | |
| // -- Wait (timed pause) -- | |
| // { type: 'wait', duration: 1500 }, | |
| // -- Character exits -- | |
| // { type: 'character', action: 'exit', characterId: 'hero' }, | |
| ]; | |
| } | |
| // ============================================================================ | |
| // OPTIONAL: Scene setup | |
| // ============================================================================ | |
| protected override createBackground(): void { | |
| // TODO: Set your background image (always check texture exists) | |
| // const cam = this.cameras.main; | |
| // if (this.textures.exists('chapter1_bg')) { | |
| // const bg = this.add.image(cam.width / 2, cam.height / 2, 'chapter1_bg'); | |
| // bg.setDisplaySize(cam.width, cam.height); | |
| // } | |
| } | |
| protected override createCharacters(): void { | |
| // TODO: Register characters used in this chapter | |
| // this.registerCharacter({ | |
| // id: 'hero', | |
| // textureKey: 'hero_neutral', | |
| // displayName: 'Alaric', | |
| // expressions: { happy: 'hero_happy', angry: 'hero_angry', sad: 'hero_sad' }, | |
| // defaultPosition: 'left', | |
| // }); | |
| } | |
| protected override getBackgroundMusicKey(): string | undefined { | |
| // TODO: Return your music key or undefined for no music | |
| // return this.cache.audio.exists('chapter1_bgm') ? 'chapter1_bgm' : undefined; | |
| return undefined; | |
| } | |
| /** | |
| * OPTIONAL: Gameplay hints displayed in top-right corner. | |
| * Return [] to hide the panel entirely. | |
| */ | |
| protected override getGameplayHints(): string[] { | |
| return [ | |
| 'Click or Enter: advance', | |
| // TODO: Add game-specific hints | |
| ]; | |
| } | |
| // ============================================================================ | |
| // OPTIONAL: Customize UI (override for non-standard UI) | |
| // ============================================================================ | |
| // -- To change dialogue box style without replacing the component: -- | |
| // protected override getDialogueBoxConfig(): DialogueBoxConfig { | |
| // const cam = this.cameras.main; | |
| // return { | |
| // x: cam.width / 2, | |
| // y: cam.height - 120, | |
| // width: 800, | |
| // height: 180, | |
| // backgroundColor: 0x222244, | |
| // backgroundAlpha: 0.85, | |
| // typeSpeed: 25, | |
| // padding: 24, | |
| // }; | |
| // } | |
| // -- To use entirely different UI (e.g., speech bubbles): -- | |
| // protected override createDialogueUI(): void { | |
| // // Create your own custom UI components here. | |
| // // Do NOT call super.createDialogueUI() if you want to replace entirely. | |
| // // Also override showDialogueText() and showChoiceUI() to use your UI. | |
| // } | |
| // | |
| // protected override showDialogueText(speaker: string, text: string, expression?: string): void { | |
| // // Display text using your custom UI component | |
| // } | |
| // | |
| // protected override showChoiceUI(prompt: string, options: ChoiceDisplayOption[]): void { | |
| // // Display choices using your custom UI. | |
| // // Call this.resolveChoice(selectedIndex) when the player picks one. | |
| // } | |
| // ============================================================================ | |
| // OPTIONAL: Event handlers | |
| // ============================================================================ | |
| protected override onDialogueEvent( | |
| action: string, | |
| data?: Record<string, any>, | |
| ): void { | |
| // Handle custom events embedded in dialogues | |
| // switch (action) { | |
| // case 'screen_shake': | |
| // this.cameras.main.shake(500, data?.intensity ?? 0.02); | |
| // break; | |
| // case 'play_sfx': | |
| // if (data?.key && this.cache.audio.exists(data.key)) { | |
| // this.sound.play(data.key); | |
| // } | |
| // break; | |
| // } | |
| } | |
| protected override onChoiceMade( | |
| choiceId: string, | |
| option: ChoiceOption, | |
| ): void { | |
| // React to specific choices | |
| // if (choiceId === 'greeting' && option.text === 'Wave back') { | |
| // this.showFloatingText('+1 Friendship', 512, 300); | |
| // } | |
| } | |
| protected override onChapterComplete(): void { | |
| // TODO: Transition to next chapter or scene | |
| // this.scene.start('Chapter2Scene'); | |
| } | |
| } | |