Add northern story art lazy loading

This commit is contained in:
2026-06-24 16:36:37 +09:00
parent 384ce7725c
commit 9fae89a55f
10 changed files with 247 additions and 343 deletions

View File

@@ -1,5 +1,6 @@
import Phaser from 'phaser';
import { soundDirector } from '../audio/SoundDirector';
import { storyBackgroundAssets } from '../data/storyAssets';
import { prologuePages, type PortraitKey, type StoryPage } from '../data/scenario';
import { palette } from '../ui/palette';
@@ -31,6 +32,7 @@ export class StoryScene extends Phaser.Scene {
private nameText?: Phaser.GameObjects.Text;
private bodyText?: Phaser.GameObjects.Text;
private progressText?: Phaser.GameObjects.Text;
private loadingText?: Phaser.GameObjects.Text;
constructor() {
super('StoryScene');
@@ -44,17 +46,86 @@ export class StoryScene extends Phaser.Scene {
this.transitioning = false;
}
getDebugState() {
const page = this.pages[this.pageIndex];
return {
scene: this.scene.key,
ready: this.loadingText === undefined && this.background !== undefined,
pageIndex: this.pageIndex,
totalPages: this.pages.length,
currentPageId: page?.id,
background: page?.background,
backgroundReady: page ? this.textures.exists(page.background) : false,
activeTexture: this.background?.texture.key ?? null
};
}
create() {
const { width, height } = this.scale;
this.add.rectangle(0, 0, width, height, 0x0b0d12).setOrigin(0);
this.background = this.add.image(width / 2, height / 2, this.pages[0].background);
this.drawSceneShade(width, height);
this.drawDialogPanel(width, height);
this.showPage(0, true);
this.createFallbackStoryTexture();
this.loadingText = this.add.text(width / 2, height / 2, '장면을 준비하는 중...', {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '22px',
color: '#f5e6b8',
stroke: '#05070a',
strokeThickness: 4
});
this.loadingText.setOrigin(0.5);
this.input.on('pointerdown', () => this.advance());
this.input.keyboard?.on('keydown-SPACE', () => this.advance());
this.input.keyboard?.on('keydown-ENTER', () => this.advance());
this.ensureStoryBackgroundsLoaded(() => {
this.loadingText?.destroy();
this.loadingText = undefined;
this.background = this.add.image(width / 2, height / 2, this.resolveBackgroundKey(this.pages[0].background));
this.drawSceneShade(width, height);
this.drawDialogPanel(width, height);
this.showPage(0, true);
this.input.on('pointerdown', () => this.advance());
this.input.keyboard?.on('keydown-SPACE', () => this.advance());
this.input.keyboard?.on('keydown-ENTER', () => this.advance());
});
}
private ensureStoryBackgroundsLoaded(onReady: () => void) {
const missingKeys = Array.from(new Set(this.pages.map((page) => page.background))).filter((key) => !this.textures.exists(key));
const loadableKeys = missingKeys.filter((key) => storyBackgroundAssets[key]);
missingKeys
.filter((key) => !storyBackgroundAssets[key])
.forEach((key) => console.warn(`Missing story background asset for ${key}`));
if (loadableKeys.length === 0) {
onReady();
return;
}
this.load.once('complete', onReady);
this.load.once('loaderror', (file: Phaser.Loader.File) => {
console.warn(`Failed to load story background ${file.key}`);
});
loadableKeys.forEach((key) => this.load.image(key, storyBackgroundAssets[key]));
this.load.start();
}
private createFallbackStoryTexture() {
if (this.textures.exists('story-fallback')) {
return;
}
const graphics = this.make.graphics({ x: 0, y: 0 });
graphics.fillStyle(0x10131a, 1);
graphics.fillRect(0, 0, 1280, 720);
graphics.fillStyle(0x1d2530, 1);
graphics.fillRect(0, 0, 1280, 180);
graphics.lineStyle(4, palette.gold, 0.5);
graphics.beginPath();
graphics.moveTo(120, 600);
graphics.lineTo(1160, 120);
graphics.strokePath();
graphics.generateTexture('story-fallback', 1280, 720);
graphics.destroy();
}
private drawSceneShade(width: number, height: number) {
@@ -197,13 +268,14 @@ export class StoryScene extends Phaser.Scene {
}
const { width, height } = this.scale;
const source = this.textures.get(textureKey).getSourceImage();
const safeTextureKey = this.resolveBackgroundKey(textureKey);
const source = this.textures.get(safeTextureKey).getSourceImage();
const imageWidth = source.width;
const imageHeight = source.height;
const coverScale = Math.max(width / imageWidth, height / imageHeight);
this.tweens.killTweensOf(this.background);
this.background.setTexture(textureKey);
this.background.setTexture(safeTextureKey);
this.background.setAlpha(1);
this.background.setScale(coverScale * 1.07);
this.background.setPosition(width / 2 - 16, height / 2);
@@ -220,6 +292,10 @@ export class StoryScene extends Phaser.Scene {
});
}
private resolveBackgroundKey(textureKey: string) {
return this.textures.exists(textureKey) ? textureKey : 'story-fallback';
}
private advance() {
if (this.transitioning) {
return;