Expand campaign visual assets
This commit is contained in:
@@ -1,29 +1,10 @@
|
||||
import Phaser from 'phaser';
|
||||
import { soundDirector } from '../audio/SoundDirector';
|
||||
import { storyBackgroundAssets } from '../data/storyAssets';
|
||||
import { portraitKeyForSpeaker, portraitTextureKey } from '../data/portraitAssets';
|
||||
import { storyBackgroundAssets, storyBackgroundKeysFor } from '../data/storyAssets';
|
||||
import { prologuePages, type PortraitKey, type StoryPage } from '../data/scenario';
|
||||
import { palette } from '../ui/palette';
|
||||
|
||||
const portraitKeys: Record<PortraitKey, string> = {
|
||||
liuBei: 'portrait-liu-bei',
|
||||
guanYu: 'portrait-guan-yu',
|
||||
zhangFei: 'portrait-zhang-fei',
|
||||
zhugeLiang: 'portrait-zhuge-liang',
|
||||
zhaoYun: 'portrait-zhao-yun',
|
||||
jiangWei: 'portrait-jiang-wei',
|
||||
simaYi: 'portrait-sima-yi'
|
||||
};
|
||||
|
||||
const portraitBySpeaker: Record<string, PortraitKey> = {
|
||||
유비: 'liuBei',
|
||||
관우: 'guanYu',
|
||||
장비: 'zhangFei',
|
||||
제갈량: 'zhugeLiang',
|
||||
조운: 'zhaoYun',
|
||||
강유: 'jiangWei',
|
||||
사마의: 'simaYi'
|
||||
};
|
||||
|
||||
type AlphaObject = Phaser.GameObjects.Image | Phaser.GameObjects.Rectangle | Phaser.GameObjects.Text;
|
||||
|
||||
type StorySceneData = {
|
||||
@@ -69,8 +50,9 @@ export class StoryScene extends Phaser.Scene {
|
||||
pageIndex: this.pageIndex,
|
||||
totalPages: this.pages.length,
|
||||
currentPageId: page?.id,
|
||||
background: page?.background,
|
||||
backgroundReady: page ? this.textures.exists(page.background) : false,
|
||||
requestedBackground: page?.background,
|
||||
background: page ? this.pageBackgroundKey(page) : undefined,
|
||||
backgroundReady: page ? this.textures.exists(this.pageBackgroundKey(page)) : false,
|
||||
activeTexture: this.background?.texture.key ?? null,
|
||||
portraitKey: page ? this.pagePortraitKey(page) ?? null : null,
|
||||
portraitTextureKey: this.portrait?.visible ? this.portrait.texture.key : null
|
||||
@@ -93,7 +75,7 @@ export class StoryScene extends Phaser.Scene {
|
||||
this.ensureStoryBackgroundsLoaded(() => {
|
||||
this.loadingText?.destroy();
|
||||
this.loadingText = undefined;
|
||||
this.background = this.add.image(width / 2, height / 2, this.resolveBackgroundKey(this.pages[0].background));
|
||||
this.background = this.add.image(width / 2, height / 2, this.resolveBackgroundKey(this.pageBackgroundKey(this.pages[0])));
|
||||
this.drawSceneShade(width, height);
|
||||
this.drawDialogPanel(width, height);
|
||||
this.showPage(0, true);
|
||||
@@ -105,7 +87,8 @@ export class StoryScene extends Phaser.Scene {
|
||||
}
|
||||
|
||||
private ensureStoryBackgroundsLoaded(onReady: () => void) {
|
||||
const missingKeys = Array.from(new Set(this.pages.map((page) => page.background))).filter((key) => !this.textures.exists(key));
|
||||
const requestedKeys = this.pages.flatMap((page) => storyBackgroundKeysFor(page.background));
|
||||
const missingKeys = Array.from(new Set(requestedKeys)).filter((key) => !this.textures.exists(key));
|
||||
const loadableKeys = missingKeys.filter((key) => storyBackgroundAssets[key]);
|
||||
|
||||
missingKeys
|
||||
@@ -252,16 +235,17 @@ export class StoryScene extends Phaser.Scene {
|
||||
|
||||
private applyPage(page: StoryPage) {
|
||||
soundDirector.playMusic(page.bgm);
|
||||
this.applyBackground(page.background);
|
||||
this.applyBackground(page);
|
||||
this.chapterText?.setText(page.chapter);
|
||||
|
||||
const portraitKey = this.pagePortraitKey(page);
|
||||
const textureKey = portraitKey ? portraitTextureKey(portraitKey) : undefined;
|
||||
|
||||
if (portraitKey) {
|
||||
if (textureKey && this.textures.exists(textureKey)) {
|
||||
this.portraitFrame?.setVisible(true);
|
||||
this.portrait?.setVisible(true);
|
||||
this.portraitDivider?.setVisible(true);
|
||||
this.portrait?.setTexture(portraitKeys[portraitKey]);
|
||||
this.portrait?.setTexture(textureKey);
|
||||
this.portrait?.setDisplaySize(128, 128);
|
||||
this.nameText?.setPosition(270, this.scale.height - 210);
|
||||
this.bodyText?.setPosition(270, this.scale.height - 160);
|
||||
@@ -281,16 +265,25 @@ export class StoryScene extends Phaser.Scene {
|
||||
}
|
||||
|
||||
private pagePortraitKey(page: StoryPage) {
|
||||
return page.portrait ?? (page.speaker ? portraitBySpeaker[page.speaker] : undefined);
|
||||
return page.portrait ?? portraitKeyForSpeaker(page.speaker);
|
||||
}
|
||||
|
||||
private applyBackground(textureKey: string) {
|
||||
private pageBackgroundKey(page: StoryPage) {
|
||||
const keys = storyBackgroundKeysFor(page.background).filter((key) => this.textures.exists(key));
|
||||
if (keys.length <= 1) {
|
||||
return keys[0] ?? page.background;
|
||||
}
|
||||
|
||||
return keys[this.hashString(page.id) % keys.length];
|
||||
}
|
||||
|
||||
private applyBackground(page: StoryPage) {
|
||||
if (!this.background) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { width, height } = this.scale;
|
||||
const safeTextureKey = this.resolveBackgroundKey(textureKey);
|
||||
const safeTextureKey = this.resolveBackgroundKey(this.pageBackgroundKey(page));
|
||||
const source = this.textures.get(safeTextureKey).getSourceImage();
|
||||
const imageWidth = source.width;
|
||||
const imageHeight = source.height;
|
||||
@@ -318,6 +311,14 @@ export class StoryScene extends Phaser.Scene {
|
||||
return this.textures.exists(textureKey) ? textureKey : 'story-fallback';
|
||||
}
|
||||
|
||||
private hashString(value: string) {
|
||||
let hash = 0;
|
||||
for (let index = 0; index < value.length; index += 1) {
|
||||
hash = (hash * 31 + value.charCodeAt(index)) >>> 0;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
private advance() {
|
||||
if (this.transitioning) {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user