feat: adopt 1920x1080 baseline

This commit is contained in:
2026-07-12 11:45:01 +09:00
parent c8e8ee4b3a
commit 3daad2861b
14 changed files with 1231 additions and 729 deletions

View File

@@ -31,6 +31,9 @@ type StorySceneData = {
const sceneShadeDepth = 1;
const cutsceneDepth = 8;
const dialogDepth = 20;
const fhdUiScale = 1.5;
const ui = (value: number) => value * fhdUiScale;
const uiPx = (value: number) => `${Math.round(ui(value))}px`;
const storyUnitFrameRows: Record<UnitDirection, number> = {
south: 0,
east: 1,
@@ -119,10 +122,10 @@ export class StoryScene extends Phaser.Scene {
this.createFallbackStoryTexture();
this.loadingText = this.add.text(width / 2, height / 2, '장면을 준비하는 중...', {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '22px',
fontSize: uiPx(22),
color: '#f5e6b8',
stroke: '#05070a',
strokeThickness: 4
strokeThickness: ui(4)
});
this.loadingText.setOrigin(0.5);
@@ -194,17 +197,18 @@ export class StoryScene extends Phaser.Scene {
return;
}
const { width, height } = this.scale;
const graphics = this.make.graphics({ x: 0, y: 0 });
graphics.fillStyle(0x10131a, 1);
graphics.fillRect(0, 0, 1280, 720);
graphics.fillRect(0, 0, width, height);
graphics.fillStyle(0x1d2530, 1);
graphics.fillRect(0, 0, 1280, 180);
graphics.lineStyle(4, palette.gold, 0.5);
graphics.fillRect(0, 0, width, height * (180 / 720));
graphics.lineStyle(ui(4), palette.gold, 0.5);
graphics.beginPath();
graphics.moveTo(120, 600);
graphics.lineTo(1160, 120);
graphics.moveTo(width * (120 / 1280), height * (600 / 720));
graphics.lineTo(width * (1160 / 1280), height * (120 / 720));
graphics.strokePath();
graphics.generateTexture('story-fallback', 1280, 720);
graphics.generateTexture('story-fallback', width, height);
graphics.destroy();
}
@@ -214,90 +218,90 @@ export class StoryScene extends Phaser.Scene {
shade.fillStyle(0x030405, 0.34);
shade.fillRect(0, 0, width, height);
shade.fillStyle(0x030405, 0.5);
shade.fillRect(0, height - 286, width, 286);
shade.fillRect(0, height - ui(286), width, ui(286));
shade.fillStyle(0x030405, 0.34);
shade.fillRect(0, 0, width, 118);
shade.fillRect(0, 0, width, ui(118));
shade.fillStyle(0x030405, 0.2);
shade.fillRect(0, 94, width, 388);
shade.fillRect(0, ui(94), width, ui(388));
shade.fillStyle(0x030405, 0.28);
shade.fillRect(0, 0, 120, height);
shade.fillRect(width - 120, 0, 120, height);
shade.fillRect(0, 0, ui(120), height);
shade.fillRect(width - ui(120), 0, ui(120), height);
}
private drawDialogPanel(width: number, height: number) {
const panelY = height - 238;
const panelX = 72;
const panelW = width - 144;
const panelH = 172;
const panelY = height - ui(238);
const panelX = ui(72);
const panelW = width - ui(144);
const panelH = ui(172);
const panel = this.add.graphics();
panel.setDepth(dialogDepth);
panel.fillStyle(cutsceneUiColors.veil, 0.62);
panel.fillRoundedRect(panelX - 12, panelY + 12, panelW + 24, panelH + 18, 12);
panel.fillRoundedRect(panelX - ui(12), panelY + ui(12), panelW + ui(24), panelH + ui(18), ui(12));
panel.fillStyle(cutsceneUiColors.woodDark, 0.96);
panel.fillRoundedRect(panelX, panelY, panelW, panelH, 10);
panel.fillRoundedRect(panelX, panelY, panelW, panelH, ui(10));
panel.fillStyle(cutsceneUiColors.lacquer, 0.9);
panel.fillRoundedRect(panelX + 12, panelY + 14, panelW - 24, panelH - 28, 8);
panel.fillRoundedRect(panelX + ui(12), panelY + ui(14), panelW - ui(24), panelH - ui(28), ui(8));
panel.fillStyle(cutsceneUiColors.silk, 0.52);
panel.fillRoundedRect(panelX + 22, panelY + 24, panelW - 44, panelH - 48, 6);
panel.fillRoundedRect(panelX + ui(22), panelY + ui(24), panelW - ui(44), panelH - ui(48), ui(6));
panel.fillStyle(cutsceneUiColors.woodLight, 0.48);
panel.fillRoundedRect(panelX + 20, panelY - 6, panelW - 40, 14, 7);
panel.fillRoundedRect(panelX + 20, panelY + panelH - 8, panelW - 40, 14, 7);
panel.lineStyle(2, palette.gold, 0.28);
panel.strokeRoundedRect(panelX + 10, panelY + 10, panelW - 20, panelH - 20, 8);
panel.lineStyle(1, 0xf0d08a, 0.12);
panel.lineBetween(panelX + 198, panelY + 24, panelX + panelW - 30, panelY + 18);
panel.lineBetween(panelX + 198, panelY + panelH - 26, panelX + panelW - 30, panelY + panelH - 18);
panel.lineStyle(1, cutsceneUiColors.woodLight, 0.14);
panel.fillRoundedRect(panelX + ui(20), panelY - ui(6), panelW - ui(40), ui(14), ui(7));
panel.fillRoundedRect(panelX + ui(20), panelY + panelH - ui(8), panelW - ui(40), ui(14), ui(7));
panel.lineStyle(ui(2), palette.gold, 0.28);
panel.strokeRoundedRect(panelX + ui(10), panelY + ui(10), panelW - ui(20), panelH - ui(20), ui(8));
panel.lineStyle(ui(1), 0xf0d08a, 0.12);
panel.lineBetween(panelX + ui(198), panelY + ui(24), panelX + panelW - ui(30), panelY + ui(18));
panel.lineBetween(panelX + ui(198), panelY + panelH - ui(26), panelX + panelW - ui(30), panelY + panelH - ui(18));
panel.lineStyle(ui(1), cutsceneUiColors.woodLight, 0.14);
for (let index = 0; index < 4; index += 1) {
const y = panelY + 40 + index * 24;
panel.lineBetween(panelX + 198, y, panelX + panelW - 36, y + (index % 2 === 0 ? 3 : -3));
const y = panelY + ui(40) + index * ui(24);
panel.lineBetween(panelX + ui(198), y, panelX + panelW - ui(36), y + ui(index % 2 === 0 ? 3 : -3));
}
this.chapterText = this.add.text(panelX, panelY - 42, '', {
this.chapterText = this.add.text(panelX, panelY - ui(42), '', {
fontFamily: '"Malgun Gothic", "Noto Sans KR", serif',
fontSize: '22px',
fontSize: uiPx(22),
color: '#d8b15f',
fontStyle: '700',
padding: { top: 4, bottom: 4 },
shadow: { offsetX: 0, offsetY: 2, color: '#05070a', blur: 6, fill: true }
padding: { top: ui(4), bottom: ui(4) },
shadow: { offsetX: 0, offsetY: ui(2), color: '#05070a', blur: ui(6), fill: true }
});
this.chapterText.setDepth(dialogDepth + 2);
this.portraitFrame = this.add.rectangle(panelX + 86, panelY + 86, 136, 136, cutsceneUiColors.ink, 0.92);
this.portraitFrame.setStrokeStyle(2, palette.gold, 0.34);
this.portraitFrame = this.add.rectangle(panelX + ui(86), panelY + ui(86), ui(136), ui(136), cutsceneUiColors.ink, 0.92);
this.portraitFrame.setStrokeStyle(ui(2), palette.gold, 0.34);
this.portraitFrame.setDepth(dialogDepth + 2);
this.portrait = this.add.image(panelX + 86, panelY + 86, this.pagePortraitTextureKey(this.pages[0]) ?? 'story-fallback');
this.portrait.setDisplaySize(128, 128);
this.portrait = this.add.image(panelX + ui(86), panelY + ui(86), this.pagePortraitTextureKey(this.pages[0]) ?? 'story-fallback');
this.portrait.setDisplaySize(ui(128), ui(128));
this.portrait.setDepth(dialogDepth + 3);
this.portraitDivider = this.add.rectangle(panelX + 170, panelY + 30, 1, panelH - 60, palette.gold, 0.12).setOrigin(0);
this.portraitDivider = this.add.rectangle(panelX + ui(170), panelY + ui(30), ui(1), panelH - ui(60), palette.gold, 0.12).setOrigin(0);
this.portraitDivider.setDepth(dialogDepth + 2);
this.nameText = this.add.text(panelX + 198, panelY + 28, '', {
this.nameText = this.add.text(panelX + ui(198), panelY + ui(28), '', {
fontFamily: '"Malgun Gothic", "Noto Sans KR", serif',
fontSize: '24px',
fontSize: uiPx(24),
color: '#f1e3c2',
fontStyle: '700',
padding: { top: 4, bottom: 4 }
padding: { top: ui(4), bottom: ui(4) }
});
this.nameText.setDepth(dialogDepth + 2);
this.bodyText = this.add.text(panelX + 198, panelY + 78, '', {
this.bodyText = this.add.text(panelX + ui(198), panelY + ui(78), '', {
fontFamily: '"Malgun Gothic", "Noto Sans KR", serif',
fontSize: '25px',
fontSize: uiPx(25),
color: '#e8dfca',
wordWrap: { width: panelW - 236, useAdvancedWrap: true },
lineSpacing: 10,
padding: { top: 4, bottom: 6 },
shadow: { offsetX: 0, offsetY: 2, color: '#05070a', blur: 5, fill: true }
wordWrap: { width: panelW - ui(236), useAdvancedWrap: true },
lineSpacing: ui(10),
padding: { top: ui(4), bottom: ui(6) },
shadow: { offsetX: 0, offsetY: ui(2), color: '#05070a', blur: ui(5), fill: true }
});
this.bodyText.setDepth(dialogDepth + 2);
this.progressText = this.add.text(width - 220, panelY + panelH + 20, '', {
this.progressText = this.add.text(width - ui(220), panelY + panelH + ui(20), '', {
fontFamily: '"Segoe UI", sans-serif',
fontSize: '15px',
fontSize: uiPx(15),
color: '#9aa3ad'
});
this.progressText.setDepth(dialogDepth + 2);
@@ -360,17 +364,17 @@ export class StoryScene extends Phaser.Scene {
this.portrait?.setVisible(true);
this.portraitDivider?.setVisible(true);
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);
this.bodyText?.setWordWrapWidth(this.scale.width - 374, true);
this.portrait?.setDisplaySize(ui(128), ui(128));
this.nameText?.setPosition(ui(270), this.scale.height - ui(210));
this.bodyText?.setPosition(ui(270), this.scale.height - ui(160));
this.bodyText?.setWordWrapWidth(this.scale.width - ui(374), true);
} else {
this.portraitFrame?.setVisible(false);
this.portrait?.setVisible(false);
this.portraitDivider?.setVisible(false);
this.nameText?.setPosition(96, this.scale.height - 210);
this.bodyText?.setPosition(96, this.scale.height - 160);
this.bodyText?.setWordWrapWidth(this.scale.width - 200, true);
this.nameText?.setPosition(ui(96), this.scale.height - ui(210));
this.bodyText?.setPosition(ui(96), this.scale.height - ui(160));
this.bodyText?.setWordWrapWidth(this.scale.width - ui(200), true);
}
this.nameText?.setText(page.speaker ?? '나레이션');
@@ -427,12 +431,12 @@ export class StoryScene extends Phaser.Scene {
this.background.setAlpha(1);
this.background.setDepth(0);
this.background.setScale(coverScale * 1.07);
this.background.setPosition(width / 2 - 16, height / 2);
this.background.setPosition(width / 2 - ui(16), height / 2);
this.tweens.add({
targets: this.background,
x: width / 2 + 16,
y: height / 2 - 8,
x: width / 2 + ui(16),
y: height / 2 - ui(8),
scale: coverScale * 1.11,
duration: 15000,
ease: 'Sine.easeInOut',
@@ -465,65 +469,65 @@ export class StoryScene extends Phaser.Scene {
const accent = cutscene.kind === 'victory' ? palette.green : cutscene.kind === 'operation' ? palette.blue : palette.gold;
const stage = this.add.graphics();
stage.fillStyle(cutsceneUiColors.veil, 0.62);
stage.fillRoundedRect(stageX - 18, stageY - 14, stageW + 36, stageH + 28, 14);
stage.fillRoundedRect(stageX - ui(18), stageY - ui(14), stageW + ui(36), stageH + ui(28), ui(14));
stage.fillStyle(cutsceneUiColors.woodDark, 0.98);
stage.fillRoundedRect(stageX, stageY, stageW, stageH, 12);
stage.fillRoundedRect(stageX, stageY, stageW, stageH, ui(12));
stage.fillStyle(cutsceneUiColors.woodMid, 0.9);
stage.fillRoundedRect(stageX + 12, stageY + 12, stageW - 24, stageH - 24, 9);
stage.fillRoundedRect(stageX + ui(12), stageY + ui(12), stageW - ui(24), stageH - ui(24), ui(9));
stage.fillStyle(cutsceneUiColors.lacquer, 0.68);
stage.fillRoundedRect(stageX + 26, stageY + 76, stageW - 52, stageH - 112, 8);
stage.fillRoundedRect(stageX + ui(26), stageY + ui(76), stageW - ui(52), stageH - ui(112), ui(8));
stage.fillStyle(cutsceneUiColors.woodLight, 0.2);
stage.fillRoundedRect(stageX + 18, stageY + 14, stageW - 36, 16, 8);
stage.fillRoundedRect(stageX + ui(18), stageY + ui(14), stageW - ui(36), ui(16), ui(8));
stage.fillStyle(cutsceneUiColors.woodDark, 0.36);
stage.fillRoundedRect(stageX + 18, stageY + stageH - 28, stageW - 36, 12, 6);
stage.lineStyle(1, accent, 0.28);
stage.strokeRoundedRect(stageX + 11, stageY + 11, stageW - 22, stageH - 22, 9);
stage.lineStyle(1, 0xf0d08a, 0.1);
stage.lineBetween(stageX + 30, stageY + 70, stageX + stageW - 30, stageY + 68);
stage.lineBetween(stageX + 30, stageY + stageH - 52, stageX + stageW - 30, stageY + stageH - 46);
stage.lineStyle(1, cutsceneUiColors.woodLight, 0.16);
stage.fillRoundedRect(stageX + ui(18), stageY + stageH - ui(28), stageW - ui(36), ui(12), ui(6));
stage.lineStyle(ui(1), accent, 0.28);
stage.strokeRoundedRect(stageX + ui(11), stageY + ui(11), stageW - ui(22), stageH - ui(22), ui(9));
stage.lineStyle(ui(1), 0xf0d08a, 0.1);
stage.lineBetween(stageX + ui(30), stageY + ui(70), stageX + stageW - ui(30), stageY + ui(68));
stage.lineBetween(stageX + ui(30), stageY + stageH - ui(52), stageX + stageW - ui(30), stageY + stageH - ui(46));
stage.lineStyle(ui(1), cutsceneUiColors.woodLight, 0.16);
for (let index = 0; index < 12; index += 1) {
const y = stageY + 28 + index * 24;
stage.lineBetween(stageX + 28, y, stageX + stageW - 28, y + (index % 2 === 0 ? 4 : -3));
const y = stageY + ui(28) + index * ui(24);
stage.lineBetween(stageX + ui(28), y, stageX + stageW - ui(28), y + ui(index % 2 === 0 ? 4 : -3));
}
stage.fillStyle(0x0a0504, 0.38);
stage.fillCircle(stageX + 28, stageY + 28, 4);
stage.fillCircle(stageX + stageW - 28, stageY + 28, 4);
stage.fillCircle(stageX + 28, stageY + stageH - 28, 4);
stage.fillCircle(stageX + stageW - 28, stageY + stageH - 28, 4);
stage.fillCircle(stageX + ui(28), stageY + ui(28), ui(4));
stage.fillCircle(stageX + stageW - ui(28), stageY + ui(28), ui(4));
stage.fillCircle(stageX + ui(28), stageY + stageH - ui(28), ui(4));
stage.fillCircle(stageX + stageW - ui(28), stageY + stageH - ui(28), ui(4));
const foldingScreen = this.add.graphics();
foldingScreen.lineStyle(1, 0xd0b16e, 0.1);
foldingScreen.lineStyle(ui(1), 0xd0b16e, 0.1);
foldingScreen.fillStyle(0x342216, 0.22);
for (let index = 0; index < 5; index += 1) {
const panelX = stageX + 26 + index * 86;
foldingScreen.fillRoundedRect(panelX, stageY + 92, 66, stageH - 134, 4);
foldingScreen.strokeRoundedRect(panelX, stageY + 92, 66, stageH - 134, 4);
const panelX = stageX + ui(26) + index * ui(86);
foldingScreen.fillRoundedRect(panelX, stageY + ui(92), ui(66), stageH - ui(134), ui(4));
foldingScreen.strokeRoundedRect(panelX, stageY + ui(92), ui(66), stageH - ui(134), ui(4));
}
const tableShadow = this.add.ellipse(stageX + stageW * 0.62, stageY + stageH - 34, stageW * 0.6, 38, 0x030405, 0.34);
const tableShadow = this.add.ellipse(stageX + stageW * 0.62, stageY + stageH - ui(34), stageW * 0.6, ui(38), 0x030405, 0.34);
const titlePlate = this.add.graphics();
titlePlate.fillStyle(cutsceneUiColors.lacquer, 0.88);
titlePlate.fillRoundedRect(stageX + 22, stageY + 18, 366, 48, 8);
titlePlate.fillRoundedRect(stageX + ui(22), stageY + ui(18), ui(366), ui(48), ui(8));
titlePlate.fillStyle(accent, 0.14);
titlePlate.fillRoundedRect(stageX + 30, stageY + 25, 34, 34, 5);
titlePlate.lineStyle(1, accent, 0.3);
titlePlate.lineBetween(stageX + 74, stageY + 25, stageX + 374, stageY + 25);
titlePlate.lineBetween(stageX + 74, stageY + 60, stageX + 374, stageY + 60);
titlePlate.lineStyle(1, 0xf0d08a, 0.12);
titlePlate.strokeRoundedRect(stageX + 22, stageY + 18, 366, 48, 8);
titlePlate.fillRoundedRect(stageX + ui(30), stageY + ui(25), ui(34), ui(34), ui(5));
titlePlate.lineStyle(ui(1), accent, 0.3);
titlePlate.lineBetween(stageX + ui(74), stageY + ui(25), stageX + ui(374), stageY + ui(25));
titlePlate.lineBetween(stageX + ui(74), stageY + ui(60), stageX + ui(374), stageY + ui(60));
titlePlate.lineStyle(ui(1), 0xf0d08a, 0.12);
titlePlate.strokeRoundedRect(stageX + ui(22), stageY + ui(18), ui(366), ui(48), ui(8));
const title = this.add.text(stageX + 34, stageY + 18, cutscene.title, {
const title = this.add.text(stageX + ui(34), stageY + ui(18), cutscene.title, {
fontFamily: '"Malgun Gothic", "Noto Sans KR", serif',
fontSize: '26px',
fontSize: uiPx(26),
color: '#f2e3bf',
fontStyle: '700',
stroke: '#05070a',
strokeThickness: 4
strokeThickness: ui(4)
});
const subtitle = this.add.text(stageX + 36, stageY + 53, cutscene.subtitle ?? '', {
const subtitle = this.add.text(stageX + ui(36), stageY + ui(53), cutscene.subtitle ?? '', {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '14px',
fontSize: uiPx(14),
color: '#cdbb94'
});
layer.add([stage, foldingScreen, tableShadow, titlePlate, title, subtitle]);
@@ -532,86 +536,86 @@ export class StoryScene extends Phaser.Scene {
private renderTacticalBoard(layer: Phaser.GameObjects.Container, cutscene: StoryCutscene) {
const stage = this.cutsceneStageBounds();
const boardX = stage.x + Math.round(stage.width * 0.36);
const boardY = stage.y + 78;
const boardY = stage.y + ui(78);
const boardW = Math.round(stage.width * 0.58);
const boardH = stage.height - 118;
const boardH = stage.height - ui(118);
const board: CutsceneBoardBounds = { x: boardX, y: boardY, width: boardW, height: boardH };
const parchment = this.add.graphics();
parchment.fillStyle(cutsceneUiColors.veil, 0.34);
parchment.fillEllipse(boardX + boardW * 0.52, boardY + boardH + 12, boardW * 0.9, 34);
parchment.fillEllipse(boardX + boardW * 0.52, boardY + boardH + ui(12), boardW * 0.9, ui(34));
parchment.fillStyle(cutsceneUiColors.woodDark, 0.92);
parchment.fillRoundedRect(boardX + 10, boardY - 10, boardW - 20, 20, 10);
parchment.fillRoundedRect(boardX + 8, boardY + boardH - 10, boardW - 16, 20, 10);
parchment.fillRoundedRect(boardX + ui(10), boardY - ui(10), boardW - ui(20), ui(20), ui(10));
parchment.fillRoundedRect(boardX + ui(8), boardY + boardH - ui(10), boardW - ui(16), ui(20), ui(10));
parchment.fillStyle(cutsceneUiColors.woodLight, 0.35);
parchment.fillRoundedRect(boardX + 22, boardY - 5, boardW - 44, 5, 3);
parchment.fillRoundedRect(boardX + 22, boardY + boardH - 5, boardW - 44, 5, 3);
parchment.fillRoundedRect(boardX + ui(22), boardY - ui(5), boardW - ui(44), ui(5), ui(3));
parchment.fillRoundedRect(boardX + ui(22), boardY + boardH - ui(5), boardW - ui(44), ui(5), ui(3));
parchment.fillStyle(cutsceneUiColors.parchmentDark, 0.94);
parchment.fillRoundedRect(boardX + 3, boardY + 4, boardW - 6, boardH - 8, 5);
parchment.fillRoundedRect(boardX + ui(3), boardY + ui(4), boardW - ui(6), boardH - ui(8), ui(5));
parchment.fillStyle(cutsceneUiColors.parchment, 0.92);
parchment.fillRoundedRect(boardX + 10, boardY + 12, boardW - 20, boardH - 24, 4);
parchment.fillRoundedRect(boardX + ui(10), boardY + ui(12), boardW - ui(20), boardH - ui(24), ui(4));
parchment.fillStyle(cutsceneUiColors.parchmentLight, 0.08);
parchment.fillEllipse(boardX + boardW * 0.5, boardY + boardH * 0.48, boardW * 0.82, boardH * 0.66);
parchment.fillStyle(cutsceneUiColors.paperEdge, 0.12);
parchment.fillRoundedRect(boardX + 10, boardY + 12, boardW - 20, 10, 4);
parchment.fillRoundedRect(boardX + 10, boardY + boardH - 22, boardW - 20, 10, 4);
parchment.fillRoundedRect(boardX + ui(10), boardY + ui(12), boardW - ui(20), ui(10), ui(4));
parchment.fillRoundedRect(boardX + ui(10), boardY + boardH - ui(22), boardW - ui(20), ui(10), ui(4));
parchment.fillStyle(0x23140c, 0.1);
parchment.fillEllipse(boardX + boardW * 0.5, boardY + boardH * 0.62, boardW * 0.72, boardH * 0.34);
parchment.lineStyle(1, cutsceneUiColors.mapInk, 0.24);
parchment.strokeRoundedRect(boardX + 8, boardY + 10, boardW - 16, boardH - 20, 5);
parchment.lineStyle(1, 0xf0d08a, 0.1);
parchment.lineBetween(boardX + 24, boardY + 20, boardX + boardW - 28, boardY + 16);
parchment.lineBetween(boardX + 26, boardY + boardH - 20, boardX + boardW - 24, boardY + boardH - 24);
parchment.lineStyle(ui(1), cutsceneUiColors.mapInk, 0.24);
parchment.strokeRoundedRect(boardX + ui(8), boardY + ui(10), boardW - ui(16), boardH - ui(20), ui(5));
parchment.lineStyle(ui(1), 0xf0d08a, 0.1);
parchment.lineBetween(boardX + ui(24), boardY + ui(20), boardX + boardW - ui(28), boardY + ui(16));
parchment.lineBetween(boardX + ui(26), boardY + boardH - ui(20), boardX + boardW - ui(24), boardY + boardH - ui(24));
parchment.fillStyle(0x3d2413, 0.16);
parchment.beginPath();
parchment.moveTo(boardX + boardW - 54, boardY + 12);
parchment.lineTo(boardX + boardW - 12, boardY + 12);
parchment.lineTo(boardX + boardW - 12, boardY + 52);
parchment.moveTo(boardX + boardW - ui(54), boardY + ui(12));
parchment.lineTo(boardX + boardW - ui(12), boardY + ui(12));
parchment.lineTo(boardX + boardW - ui(12), boardY + ui(52));
parchment.closePath();
parchment.fillPath();
parchment.lineStyle(1, 0x3d2413, 0.1);
parchment.lineStyle(ui(1), 0x3d2413, 0.1);
for (let index = 0; index < 11; index += 1) {
const y = boardY + 38 + index * 14;
const xOffset = index % 3 === 0 ? 26 : index % 3 === 1 ? 38 : 31;
parchment.lineBetween(boardX + xOffset, y, boardX + boardW - 30, y + (index % 2 === 0 ? 2 : -2));
const y = boardY + ui(38) + index * ui(14);
const xOffset = ui(index % 3 === 0 ? 26 : index % 3 === 1 ? 38 : 31);
parchment.lineBetween(boardX + xOffset, y, boardX + boardW - ui(30), y + ui(index % 2 === 0 ? 2 : -2));
}
for (let index = 0; index < 30; index += 1) {
const x = boardX + 30 + ((index * 47) % Math.max(60, boardW - 62));
const y = boardY + 34 + ((index * 29) % Math.max(60, boardH - 66));
const x = boardX + ui(30) + ((index * ui(47)) % Math.max(ui(60), boardW - ui(62)));
const y = boardY + ui(34) + ((index * ui(29)) % Math.max(ui(60), boardH - ui(66)));
parchment.fillStyle(index % 2 === 0 ? 0x4f3219 : 0xd2b172, 0.1);
parchment.fillCircle(x, y, index % 3 === 0 ? 1.4 : 0.9);
parchment.fillCircle(x, y, ui(index % 3 === 0 ? 1.4 : 0.9));
}
layer.add(parchment);
const map = this.add.graphics();
map.lineStyle(1, cutsceneUiColors.mapInk, 0.08);
map.lineStyle(ui(1), cutsceneUiColors.mapInk, 0.08);
for (let index = 1; index < 7; index += 1) {
const x = boardX + (boardW / 7) * index;
map.lineBetween(x, boardY + 24, x, boardY + boardH - 24);
map.lineBetween(x, boardY + ui(24), x, boardY + boardH - ui(24));
}
for (let index = 1; index < 4; index += 1) {
const y = boardY + (boardH / 4) * index;
map.lineBetween(boardX + 24, y, boardX + boardW - 24, y);
map.lineBetween(boardX + ui(24), y, boardX + boardW - ui(24), y);
}
map.fillStyle(0x365238, 0.18);
map.fillEllipse(boardX + boardW * 0.35, boardY + boardH * 0.58, boardW * 0.42, boardH * 0.46);
map.fillStyle(0x36465b, 0.14);
map.fillEllipse(boardX + boardW * 0.72, boardY + boardH * 0.36, boardW * 0.28, boardH * 0.28);
map.lineStyle(8, 0x6b4826, 0.18);
map.lineStyle(ui(8), 0x6b4826, 0.18);
map.beginPath();
map.moveTo(boardX + boardW * 0.16, boardY + boardH * 0.74);
map.lineTo(boardX + boardW * 0.38, boardY + boardH * 0.54);
map.lineTo(boardX + boardW * 0.66, boardY + boardH * 0.36);
map.lineTo(boardX + boardW * 0.83, boardY + boardH * 0.24);
map.strokePath();
map.lineStyle(2, cutsceneUiColors.mapInk, 0.22);
map.lineStyle(ui(2), cutsceneUiColors.mapInk, 0.22);
map.beginPath();
map.moveTo(boardX + boardW * 0.16, boardY + boardH * 0.74);
map.lineTo(boardX + boardW * 0.38, boardY + boardH * 0.54);
map.lineTo(boardX + boardW * 0.66, boardY + boardH * 0.36);
map.lineTo(boardX + boardW * 0.83, boardY + boardH * 0.24);
map.strokePath();
map.lineStyle(1, cutsceneUiColors.mapInk, 0.18);
map.strokeRoundedRect(boardX + 26, boardY + 28, boardW - 52, boardH - 56, 4);
map.lineStyle(ui(1), cutsceneUiColors.mapInk, 0.18);
map.strokeRoundedRect(boardX + ui(26), boardY + ui(28), boardW - ui(52), boardH - ui(56), ui(4));
layer.add(map);
this.renderBoardLegend(layer, cutscene, board);
@@ -625,14 +629,14 @@ export class StoryScene extends Phaser.Scene {
const label = cutscene.kind === 'victory' ? 'RESULT MAP' : cutscene.kind === 'operation' ? 'TACTICAL MAP' : 'SORTIE BOARD';
const bg = this.add.graphics();
bg.fillStyle(cutsceneUiColors.mapInk, 0.18);
bg.fillRoundedRect(board.x + 24, board.y + 24, 126, 22, 4);
bg.lineStyle(1, cutsceneUiColors.mapInk, 0.18);
bg.lineBetween(board.x + 32, board.y + 43, board.x + 140, board.y + 43);
bg.fillRoundedRect(board.x + ui(24), board.y + ui(24), ui(126), ui(22), ui(4));
bg.lineStyle(ui(1), cutsceneUiColors.mapInk, 0.18);
bg.lineBetween(board.x + ui(32), board.y + ui(43), board.x + ui(140), board.y + ui(43));
bg.fillStyle(cutsceneUiColors.sealRed, 0.22);
bg.fillCircle(board.x + 134, board.y + 35, 8);
const text = this.add.text(board.x + 34, board.y + 28, label, {
bg.fillCircle(board.x + ui(134), board.y + ui(35), ui(8));
const text = this.add.text(board.x + ui(34), board.y + ui(28), label, {
fontFamily: '"Segoe UI", sans-serif',
fontSize: '12px',
fontSize: uiPx(12),
color: '#ead6aa',
fontStyle: '700'
});
@@ -646,21 +650,21 @@ export class StoryScene extends Phaser.Scene {
) {
const stage = this.cutsceneStageBounds();
const actors = (cutscene.actors ?? []).filter((actor) => actor.unitId !== 'rebel-leader').slice(0, 3);
const cardX = stage.x + 28;
const cardW = Math.max(250, board.x - cardX - 24);
const cardH = actors.length >= 4 ? 60 : 70;
const firstY = stage.y + 86;
const cardX = stage.x + ui(28);
const cardW = Math.max(ui(250), board.x - cardX - ui(24));
const cardH = ui(actors.length >= 4 ? 60 : 70);
const firstY = stage.y + ui(86);
actors.forEach((actor, index) => {
const y = firstY + index * (cardH + 10);
const y = firstY + index * (cardH + ui(10));
this.renderCutsceneActorCard(layer, actor, cardX, y, cardW, cardH, index);
});
if ((cutscene.briefing?.lines ?? []).length > 0) {
const briefingY = firstY + actors.length * (cardH + 10) + 4;
const maxH = stage.y + stage.height - 36 - briefingY;
if (maxH >= 70) {
this.renderBriefingCard(layer, cutscene, cardX, briefingY, cardW, Math.min(126, maxH));
const briefingY = firstY + actors.length * (cardH + ui(10)) + ui(4);
const maxH = stage.y + stage.height - ui(36) - briefingY;
if (maxH >= ui(70)) {
this.renderBriefingCard(layer, cutscene, cardX, briefingY, cardW, Math.min(ui(126), maxH));
}
}
}
@@ -681,72 +685,72 @@ export class StoryScene extends Phaser.Scene {
const card = this.add.graphics();
card.fillStyle(cutsceneUiColors.veil, 0.34);
card.fillRoundedRect(x + 5, y + 7, width, height, 8);
card.fillRoundedRect(x + ui(5), y + ui(7), width, height, ui(8));
card.fillStyle(cutsceneUiColors.woodDark, 0.94);
card.fillRoundedRect(x, y, width, height, 8);
card.fillRoundedRect(x, y, width, height, ui(8));
card.fillStyle(cutsceneUiColors.lacquerLight, 0.46);
card.fillRoundedRect(x + 7, y + 7, width - 14, height - 14, 6);
card.fillRoundedRect(x + ui(7), y + ui(7), width - ui(14), height - ui(14), ui(6));
card.fillStyle(cutsceneUiColors.lacquer, 0.42);
card.fillRoundedRect(x + 72, y + 9, width - 88, height - 18, 5);
card.fillRoundedRect(x + ui(72), y + ui(9), width - ui(88), height - ui(18), ui(5));
card.fillStyle(profile.color, 0.42);
card.fillRoundedRect(x + 11, y + 10, 4, height - 20, 2);
card.fillRoundedRect(x + ui(11), y + ui(10), ui(4), height - ui(20), ui(2));
card.fillStyle(cutsceneUiColors.paperEdge, 0.16);
card.fillRoundedRect(x + height + 4, y + 9, Math.min(130, width - height - 52), 24, 4);
card.lineStyle(1, 0xf0d08a, 0.14);
card.lineBetween(x + 22, y + 9, x + width - 24, y + 9);
card.lineBetween(x + 22, y + height - 9, x + width - 24, y + height - 9);
card.lineStyle(1, profile.color, 0.24);
card.lineBetween(x + 18, y + 15, x + 18, y + height - 15);
card.fillRoundedRect(x + height + ui(4), y + ui(9), Math.min(ui(130), width - height - ui(52)), ui(24), ui(4));
card.lineStyle(ui(1), 0xf0d08a, 0.14);
card.lineBetween(x + ui(22), y + ui(9), x + width - ui(24), y + ui(9));
card.lineBetween(x + ui(22), y + height - ui(9), x + width - ui(24), y + height - ui(9));
card.lineStyle(ui(1), profile.color, 0.24);
card.lineBetween(x + ui(18), y + ui(15), x + ui(18), y + height - ui(15));
card.fillStyle(profile.color, 0.18);
card.fillCircle(x + width - 24, y + height / 2, 12);
card.fillCircle(x + width - ui(24), y + height / 2, ui(12));
card.fillStyle(cutsceneUiColors.sealRed, 0.18);
card.fillCircle(x + width - 24, y + height / 2, 7);
card.fillCircle(x + width - ui(24), y + height / 2, ui(7));
layer.add(card);
const portraitTexture = this.actorPortraitTextureKey(actor, index);
const portraitX = x + 38;
const portraitX = x + ui(38);
const portraitY = y + height / 2;
const portraitFrame = this.add.graphics();
portraitFrame.fillStyle(cutsceneUiColors.ink, 0.92);
portraitFrame.fillRoundedRect(portraitX - (height - 14) / 2, portraitY - (height - 14) / 2, height - 14, height - 14, 5);
portraitFrame.lineStyle(1, profile.color, 0.34);
portraitFrame.strokeRoundedRect(portraitX - (height - 14) / 2, portraitY - (height - 14) / 2, height - 14, height - 14, 5);
portraitFrame.lineStyle(1, 0xf0d08a, 0.1);
portraitFrame.strokeRoundedRect(portraitX - (height - 24) / 2, portraitY - (height - 24) / 2, height - 24, height - 24, 3);
portraitFrame.fillRoundedRect(portraitX - (height - ui(14)) / 2, portraitY - (height - ui(14)) / 2, height - ui(14), height - ui(14), ui(5));
portraitFrame.lineStyle(ui(1), profile.color, 0.34);
portraitFrame.strokeRoundedRect(portraitX - (height - ui(14)) / 2, portraitY - (height - ui(14)) / 2, height - ui(14), height - ui(14), ui(5));
portraitFrame.lineStyle(ui(1), 0xf0d08a, 0.1);
portraitFrame.strokeRoundedRect(portraitX - (height - ui(24)) / 2, portraitY - (height - ui(24)) / 2, height - ui(24), height - ui(24), ui(3));
layer.add(portraitFrame);
if (portraitTexture) {
const portrait = this.add.image(portraitX, portraitY, portraitTexture);
portrait.setDisplaySize(height - 18, height - 18);
portrait.setDisplaySize(height - ui(18), height - ui(18));
layer.add(portrait);
} else if (this.textures.exists(profile.unitTextureKey)) {
const sprite = this.add.sprite(portraitX, portraitY + 3, profile.unitTextureKey, this.storyUnitFrameIndex(actor.direction ?? 'south'));
sprite.setDisplaySize(height - 8, height - 8);
const sprite = this.add.sprite(portraitX, portraitY + ui(3), profile.unitTextureKey, this.storyUnitFrameIndex(actor.direction ?? 'south'));
sprite.setDisplaySize(height - ui(8), height - ui(8));
layer.add(sprite);
}
const name = this.add.text(x + height + 14, y + 11, actor.label ?? profile.name, {
const name = this.add.text(x + height + ui(14), y + ui(11), actor.label ?? profile.name, {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '16px',
fontSize: uiPx(16),
color: '#f5e6c8',
fontStyle: '700'
});
const roleBg = this.add.graphics();
roleBg.lineStyle(1, profile.color, 0.26);
roleBg.lineBetween(x + height + 14, y + 38, x + height + Math.min(128, width - height - 34), y + 38);
const role = this.add.text(x + height + 14, y + 42, profile.roleLabel, {
roleBg.lineStyle(ui(1), profile.color, 0.26);
roleBg.lineBetween(x + height + ui(14), y + ui(38), x + height + Math.min(ui(128), width - height - ui(34)), y + ui(38));
const role = this.add.text(x + height + ui(14), y + ui(42), profile.roleLabel, {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '12px',
fontSize: uiPx(12),
color: '#ddc99f'
});
layer.add([roleBg, name, role]);
if (actor.line && height >= 66) {
const line = this.add.text(x + 144, y + 50, actor.line, {
if (actor.line && height >= ui(66)) {
const line = this.add.text(x + ui(144), y + ui(50), actor.line, {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '11px',
fontSize: uiPx(11),
color: '#d8cbb2',
wordWrap: { width: width - 166, useAdvancedWrap: true }
wordWrap: { width: width - ui(166), useAdvancedWrap: true }
});
layer.add(line);
}
@@ -766,29 +770,29 @@ export class StoryScene extends Phaser.Scene {
const y = board.y + board.height * Phaser.Math.Clamp(normalizedY, 0.18, 0.82);
const sideColor = actor.unitId === 'rebel-leader' ? 0xd46a4c : profile.color;
const token = this.add.container(x, y);
const shadow = this.add.ellipse(2, 12, 38, 12, 0x05070a, 0.28);
const base = this.add.ellipse(0, 6, 30, 18, cutsceneUiColors.woodDark, 0.78);
base.setStrokeStyle(1, sideColor, 0.46);
const pin = this.add.circle(0, 6, 3, sideColor, 0.86);
pin.setStrokeStyle(1, 0x05070a, 0.62);
const shadow = this.add.ellipse(ui(2), ui(12), ui(38), ui(12), 0x05070a, 0.28);
const base = this.add.ellipse(0, ui(6), ui(30), ui(18), cutsceneUiColors.woodDark, 0.78);
base.setStrokeStyle(ui(1), sideColor, 0.46);
const pin = this.add.circle(0, ui(6), ui(3), sideColor, 0.86);
pin.setStrokeStyle(ui(1), 0x05070a, 0.62);
token.add([shadow, base, pin]);
if (this.textures.exists(profile.unitTextureKey)) {
const sprite = this.add.sprite(0, -8, profile.unitTextureKey, this.storyUnitFrameIndex(actor.direction ?? 'south'));
sprite.setDisplaySize(34, 34);
const sprite = this.add.sprite(0, -ui(8), profile.unitTextureKey, this.storyUnitFrameIndex(actor.direction ?? 'south'));
sprite.setDisplaySize(ui(34), ui(34));
token.add(sprite);
} else {
const fallback = this.add.rectangle(0, -8, 22, 24, sideColor, 0.9);
fallback.setStrokeStyle(1, 0x05070a, 0.82);
const fallback = this.add.rectangle(0, -ui(8), ui(22), ui(24), sideColor, 0.9);
fallback.setStrokeStyle(ui(1), 0x05070a, 0.82);
token.add(fallback);
}
const label = this.add.text(0, 14, actor.label ?? profile.name, {
const label = this.add.text(0, ui(14), actor.label ?? profile.name, {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '9px',
fontSize: uiPx(9),
color: '#ead9b8',
stroke: '#05070a',
strokeThickness: 2
strokeThickness: ui(2)
});
label.setOrigin(0.5, 0);
token.add(label);
@@ -804,54 +808,54 @@ export class StoryScene extends Phaser.Scene {
const bg = this.add.graphics();
bg.fillStyle(cutsceneUiColors.veil, 0.28);
bg.fillRoundedRect(x + 4, y + 5, width, height, 8);
bg.fillRoundedRect(x + ui(4), y + ui(5), width, height, ui(8));
bg.fillStyle(cutsceneUiColors.lacquer, 0.68);
bg.fillRoundedRect(x, y, width, height, 8);
bg.fillRoundedRect(x, y, width, height, ui(8));
bg.fillStyle(cutsceneUiColors.paperEdge, 0.08);
bg.fillRoundedRect(x + 10, y + 10, width - 20, height - 20, 6);
bg.lineStyle(1, palette.gold, 0.18);
bg.lineBetween(x + 16, y + 13, x + width - 16, y + 13);
bg.lineBetween(x + 16, y + height - 13, x + width - 16, y + height - 13);
const title = this.add.text(x + 18, y + 16, cutscene.briefing?.title ?? '전황', {
bg.fillRoundedRect(x + ui(10), y + ui(10), width - ui(20), height - ui(20), ui(6));
bg.lineStyle(ui(1), palette.gold, 0.18);
bg.lineBetween(x + ui(16), y + ui(13), x + width - ui(16), y + ui(13));
bg.lineBetween(x + ui(16), y + height - ui(13), x + width - ui(16), y + height - ui(13));
const title = this.add.text(x + ui(18), y + ui(16), cutscene.briefing?.title ?? '전황', {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '18px',
fontSize: uiPx(18),
color: '#d8b15f',
fontStyle: '700'
});
layer.add([bg, title]);
briefingLines.slice(0, 4).forEach((line, index) => {
const bullet = this.add.circle(x + 24, y + 54 + index * 30, 3, palette.gold, 0.72);
const text = this.add.text(x + 38, y + 43 + index * 30, line, {
const bullet = this.add.circle(x + ui(24), y + ui(54) + index * ui(30), ui(3), palette.gold, 0.72);
const text = this.add.text(x + ui(38), y + ui(43) + index * ui(30), line, {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '14px',
fontSize: uiPx(14),
color: '#d8cbb2',
wordWrap: { width: width - 58, useAdvancedWrap: true }
wordWrap: { width: width - ui(58), useAdvancedWrap: true }
});
layer.add([bullet, text]);
});
}
private renderOperationBoard(layer: Phaser.GameObjects.Container, cutscene: StoryCutscene) {
const boardX = this.scale.width - 560;
const boardY = 128;
const boardW = 474;
const boardH = 246;
const boardX = this.scale.width - ui(560);
const boardY = ui(128);
const boardW = ui(474);
const boardH = ui(246);
const board = this.add.rectangle(boardX, boardY, boardW, boardH, 0x0b1218, 0.92).setOrigin(0);
board.setStrokeStyle(1, palette.blue, 0.5);
board.setStrokeStyle(ui(1), palette.blue, 0.5);
layer.add(board);
const grid = this.add.graphics();
grid.lineStyle(1, 0x53606c, 0.26);
grid.lineStyle(ui(1), 0x53606c, 0.26);
for (let i = 1; i < 6; i += 1) {
const x = boardX + (boardW / 6) * i;
grid.lineBetween(x, boardY + 16, x, boardY + boardH - 16);
grid.lineBetween(x, boardY + ui(16), x, boardY + boardH - ui(16));
}
for (let i = 1; i < 4; i += 1) {
const y = boardY + (boardH / 4) * i;
grid.lineBetween(boardX + 16, y, boardX + boardW - 16, y);
grid.lineBetween(boardX + ui(16), y, boardX + boardW - ui(16), y);
}
grid.lineStyle(3, palette.gold, 0.36);
grid.lineStyle(ui(3), palette.gold, 0.36);
grid.beginPath();
grid.moveTo(boardX + boardW * 0.2, boardY + boardH * 0.74);
grid.lineTo(boardX + boardW * 0.44, boardY + boardH * 0.5);
@@ -859,7 +863,7 @@ export class StoryScene extends Phaser.Scene {
grid.strokePath();
layer.add(grid);
this.renderBriefingCard(layer, cutscene, 82, 184, 364, 138);
this.renderBriefingCard(layer, cutscene, ui(82), ui(184), ui(364), ui(138));
(cutscene.markers ?? []).forEach((marker) => this.renderOperationMarker(layer, marker, boardX, boardY, boardW, boardH));
}
@@ -875,18 +879,18 @@ export class StoryScene extends Phaser.Scene {
const color = marker.side === 'ally' ? palette.blue : marker.side === 'enemy' ? 0xd46a4c : palette.gold;
const x = boardX + boardW * marker.x;
const y = boardY + boardH * marker.y;
const halo = this.add.circle(x, y, 9, color, 0.1);
const dot = this.add.circle(x, y, 4, color, 0.86);
dot.setStrokeStyle(1, cutsceneUiColors.mapInk, 0.72);
const stem = this.add.rectangle(x - 0.5, y + 4, 1, 13, color, 0.42).setOrigin(0, 0);
const labelX = marker.side === 'objective' ? x - 8 : x + 11;
const labelY = marker.side === 'objective' ? y - 27 : y - 10;
const halo = this.add.circle(x, y, ui(9), color, 0.1);
const dot = this.add.circle(x, y, ui(4), color, 0.86);
dot.setStrokeStyle(ui(1), cutsceneUiColors.mapInk, 0.72);
const stem = this.add.rectangle(x - ui(0.5), y + ui(4), ui(1), ui(13), color, 0.42).setOrigin(0, 0);
const labelX = marker.side === 'objective' ? x - ui(8) : x + ui(11);
const labelY = marker.side === 'objective' ? y - ui(27) : y - ui(10);
const label = this.add.text(labelX, labelY, marker.label, {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '11px',
fontSize: uiPx(11),
color: '#ead9b8',
stroke: '#05070a',
strokeThickness: 2
strokeThickness: ui(2)
});
if (marker.side === 'objective') {
label.setOrigin(0.5, 0);
@@ -902,7 +906,7 @@ export class StoryScene extends Phaser.Scene {
const x = this.scale.width * actor.x;
const y = this.scale.height * actor.y;
const size = actor.size ?? 126;
const size = ui(actor.size ?? 126);
const direction = actor.direction ?? 'south';
const shadow = this.add.ellipse(x, y + size * 0.36, size * 0.46, size * 0.14, 0x05070a, 0.56);
layer.add(shadow);
@@ -914,7 +918,7 @@ export class StoryScene extends Phaser.Scene {
layer.add(sprite);
this.tweens.add({
targets: sprite,
y: y - 4,
y: y - ui(4),
duration: 1200 + index * 90,
ease: 'Sine.easeInOut',
yoyo: true,
@@ -923,16 +927,16 @@ export class StoryScene extends Phaser.Scene {
});
} else {
const fallback = this.add.rectangle(x, y, size * 0.56, size * 0.86, profile.color, 0.88);
fallback.setStrokeStyle(2, 0x05070a, 0.8);
fallback.setStrokeStyle(ui(2), 0x05070a, 0.8);
layer.add(fallback);
}
const labelWidth = Math.max(78, Math.min(132, size * 0.86));
const labelBg = this.add.rectangle(x, y + size * 0.54, labelWidth, 28, 0x070b10, 0.9);
labelBg.setStrokeStyle(1, profile.color, 0.64);
const label = this.add.text(x, y + size * 0.54 - 7, actor.label ?? profile.name, {
const labelWidth = Math.max(ui(78), Math.min(ui(132), size * 0.86));
const labelBg = this.add.rectangle(x, y + size * 0.54, labelWidth, ui(28), 0x070b10, 0.9);
labelBg.setStrokeStyle(ui(1), profile.color, 0.64);
const label = this.add.text(x, y + size * 0.54 - ui(7), actor.label ?? profile.name, {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '13px',
fontSize: uiPx(13),
color: '#f2e3bf',
fontStyle: '700'
});
@@ -942,12 +946,12 @@ export class StoryScene extends Phaser.Scene {
if (actor.line) {
const line = this.add.text(x, y - size * 0.58, actor.line, {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '12px',
fontSize: uiPx(12),
color: '#e8dfca',
align: 'center',
wordWrap: { width: 160, useAdvancedWrap: true },
wordWrap: { width: ui(160), useAdvancedWrap: true },
stroke: '#05070a',
strokeThickness: 3
strokeThickness: ui(3)
});
line.setOrigin(0.5, 1);
layer.add(line);
@@ -961,18 +965,18 @@ export class StoryScene extends Phaser.Scene {
const stage = this.cutsceneStageBounds();
const maxItems = Math.min(4, rewards.length);
const stripX = stage.x + 28;
const stripY = stage.y + stage.height - 44;
const stripW = stage.width - 56;
const stripX = stage.x + ui(28);
const stripY = stage.y + stage.height - ui(44);
const stripW = stage.width - ui(56);
const itemW = Math.floor(stripW / maxItems);
const bg = this.add.graphics();
bg.fillStyle(cutsceneUiColors.veil, 0.22);
bg.fillRoundedRect(stripX + 4, stripY + 5, stripW, 34, 6);
bg.fillRoundedRect(stripX + ui(4), stripY + ui(5), stripW, ui(34), ui(6));
bg.fillStyle(cutsceneUiColors.lacquer, 0.72);
bg.fillRoundedRect(stripX, stripY, stripW, 34, 6);
bg.lineStyle(1, palette.gold, 0.18);
bg.lineBetween(stripX + 12, stripY + 6, stripX + stripW - 12, stripY + 6);
bg.lineBetween(stripX + 12, stripY + 28, stripX + stripW - 12, stripY + 28);
bg.fillRoundedRect(stripX, stripY, stripW, ui(34), ui(6));
bg.lineStyle(ui(1), palette.gold, 0.18);
bg.lineBetween(stripX + ui(12), stripY + ui(6), stripX + stripW - ui(12), stripY + ui(6));
bg.lineBetween(stripX + ui(12), stripY + ui(28), stripX + stripW - ui(12), stripY + ui(28));
layer.add(bg);
rewards.slice(0, maxItems).forEach((reward, index) => {
@@ -980,17 +984,17 @@ export class StoryScene extends Phaser.Scene {
const x = stripX + index * itemW;
const item = this.add.graphics();
item.fillStyle(toneColor, 0.16);
item.fillCircle(x + 17, stripY + 17, 5);
item.lineStyle(1, toneColor, 0.22);
item.fillCircle(x + ui(17), stripY + ui(17), ui(5));
item.lineStyle(ui(1), toneColor, 0.22);
if (index > 0) {
item.lineBetween(x, stripY + 9, x, stripY + 25);
item.lineBetween(x, stripY + ui(9), x, stripY + ui(25));
}
const text = this.add.text(x + 30, stripY + 8, reward.label, {
const text = this.add.text(x + ui(30), stripY + ui(8), reward.label, {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '13px',
fontSize: uiPx(13),
color: '#f2e3bf',
fontStyle: '700',
wordWrap: { width: itemW - 40, useAdvancedWrap: true }
wordWrap: { width: itemW - ui(40), useAdvancedWrap: true }
});
layer.add([item, text]);
});
@@ -998,10 +1002,10 @@ export class StoryScene extends Phaser.Scene {
private cutsceneStageBounds(): CutsceneStageBounds {
return {
x: 58,
y: 98,
width: this.scale.width - 116,
height: 348
x: ui(58),
y: ui(98),
width: this.scale.width - ui(116),
height: ui(348)
};
}