Scaffold tactical RPG web prototype

This commit is contained in:
2026-06-21 22:20:31 +09:00
parent 2f0810dd2e
commit 764df7edce
17 changed files with 1364 additions and 0 deletions

View File

@@ -0,0 +1,85 @@
import Phaser from 'phaser';
import { prologueLines, type StoryLine } from '../data/scenario';
import { palette } from '../ui/palette';
const portraitKeys: Record<StoryLine['portrait'], string> = {
lord: 'portrait-lord',
strategist: 'portrait-strategist',
captain: 'portrait-captain'
};
export class StoryScene extends Phaser.Scene {
private lineIndex = 0;
private portrait?: Phaser.GameObjects.Image;
private nameText?: Phaser.GameObjects.Text;
private bodyText?: Phaser.GameObjects.Text;
constructor() {
super('StoryScene');
}
create() {
const { width, height } = this.scale;
this.add.rectangle(0, 0, width, height, 0x151922).setOrigin(0);
this.drawCampBackground(width, height);
this.drawDialogPanel(width, height);
this.showLine(0);
this.input.on('pointerdown', () => this.advance());
this.input.keyboard?.on('keydown-SPACE', () => this.advance());
this.input.keyboard?.on('keydown-ENTER', () => this.advance());
}
private drawCampBackground(width: number, height: number) {
const graphics = this.add.graphics();
graphics.fillStyle(0x26303a, 1);
graphics.fillRect(0, height * 0.54, width, height * 0.46);
graphics.fillStyle(0x5f6d5a, 1);
graphics.fillTriangle(0, height * 0.54, 240, 240, 470, height * 0.54);
graphics.fillStyle(0x384858, 1);
graphics.fillTriangle(300, height * 0.54, 570, 160, 870, height * 0.54);
graphics.fillStyle(0x8a4f3d, 1);
graphics.fillRect(935, 264, 98, 200);
graphics.fillStyle(0xd8b15f, 1);
graphics.fillTriangle(1033, 264, 1180, 304, 1033, 344);
}
private drawDialogPanel(width: number, height: number) {
const panelY = height - 214;
this.add.rectangle(64, panelY, width - 128, 158, palette.panel, 0.95).setOrigin(0);
this.add.rectangle(64, panelY, width - 128, 4, palette.gold, 0.9).setOrigin(0);
this.portrait = this.add.image(150, panelY + 79, 'portrait-lord');
this.nameText = this.add.text(238, panelY + 28, '', {
fontSize: '24px',
color: '#d8b15f',
fontStyle: '700'
});
this.bodyText = this.add.text(238, panelY + 68, '', {
fontSize: '24px',
color: '#e8dfca',
wordWrap: { width: width - 370, useAdvancedWrap: true },
lineSpacing: 8
});
this.add.text(width - 190, panelY + 122, 'SPACE / ENTER', {
fontSize: '16px',
color: '#9aa3ad'
});
}
private showLine(index: number) {
const line = prologueLines[index];
this.portrait?.setTexture(portraitKeys[line.portrait]);
this.nameText?.setText(line.speaker);
this.bodyText?.setText(line.text);
}
private advance() {
if (this.lineIndex >= prologueLines.length - 1) {
this.scene.start('BattleScene');
return;
}
this.lineIndex += 1;
this.showLine(this.lineIndex);
}
}