Improve strategy and item UI clarity

This commit is contained in:
2026-07-02 20:25:45 +09:00
parent db04e2a2a9
commit e5706dc71f

View File

@@ -1327,6 +1327,18 @@ type BattleUsable = {
description: string;
};
type SupportPreview = {
usable: BattleUsable;
user: UnitData;
target: UnitData;
healAmount: number;
projectedHp: number;
attackBonus: number;
hitBonus: number;
criticalBonus: number;
duration: number;
};
type SupportResult = {
usable: BattleUsable;
user: UnitData;
@@ -4218,6 +4230,91 @@ export class BattleScene extends Phaser.Scene {
};
}
private usableAccentColor(usable: BattleUsable) {
if (usable.command === 'item') {
return palette.gold;
}
if (usable.effect === 'heal') {
return palette.green;
}
if (usable.effect === 'focus') {
return palette.blue;
}
return 0xb64a45;
}
private usableEffectLabel(usable: BattleUsable) {
if (usable.effect === 'heal') {
return '회복';
}
if (usable.effect === 'focus') {
return '강화';
}
return '피해';
}
private usableTargetLabel(usable: BattleUsable) {
if (usable.target === 'self') {
return '자신';
}
if (usable.target === 'ally') {
return '아군';
}
return '적군';
}
private usablePowerLabel(usable: BattleUsable) {
if (usable.effect === 'heal') {
return `회복 ${usable.power}+`;
}
if (usable.effect === 'focus') {
return `${usable.duration ?? 1}턴 강화`;
}
return `위력 ${usable.power}`;
}
private usableTargetCount(user: UnitData, usable: BattleUsable) {
if (usable.effect === 'damage') {
return this.damageableTargets(user, usable.command, usable).length;
}
return this.supportTargets(user, usable).length;
}
private usableStockLabel(user: UnitData, usable: BattleUsable) {
return usable.command === 'item' ? `보유 ${this.itemStock(user.id, usable.id)}` : '책략';
}
private usableDetailText(user: UnitData, usable: BattleUsable) {
const targetCount = this.usableTargetCount(user, usable);
return [
`${usable.name} / ${this.usableEffectLabel(usable)} / ${this.usableTargetLabel(usable)}`,
`${this.usablePowerLabel(usable)} · 사거리 ${usable.range} · 대상 ${targetCount}`,
usable.description
].join('\n');
}
private renderUsableMenuPill(x: number, y: number, width: number, icon: BattleUiIconKey, label: string, tone: number) {
const pill = this.add.rectangle(x, y, width, 22, 0x0b1118, 0.92);
pill.setOrigin(0);
pill.setDepth(16);
pill.setStrokeStyle(1, tone, 0.54);
this.commandMenuObjects.push(pill);
const iconImage = this.createBattleUiIcon(x + 12, y + 11, icon, 16);
iconImage.setDepth(17);
this.commandMenuObjects.push(iconImage);
const text = this.add.text(x + 25, y + 5, label, {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '10px',
color: '#d4dce6',
fontStyle: '700',
fixedWidth: width - 29
});
text.setDepth(17);
this.commandMenuObjects.push(text);
}
private hideCommandMenu() {
this.commandMenuObjects.forEach((object) => object.destroy());
this.commandMenuObjects = [];
@@ -4237,12 +4334,13 @@ export class BattleScene extends Phaser.Scene {
this.hideCommandMenu();
const menuWidth = 276;
const titleHeight = 34;
const rowHeight = 58;
const menuWidth = 322;
const titleHeight = 36;
const rowHeight = 72;
const padding = 9;
const menuHeight = padding * 2 + titleHeight + usables.length * rowHeight;
const { left, top } = this.commandMenuPosition(pointerX, pointerY, menuWidth, menuHeight);
const titleLabel = command === 'strategy' ? '책략 선택' : '도구 선택';
const panel = this.add.rectangle(left, top, menuWidth, menuHeight, 0x101821, 0.98);
panel.setOrigin(0);
@@ -4250,9 +4348,9 @@ export class BattleScene extends Phaser.Scene {
panel.setDepth(14);
this.commandMenuObjects.push(panel);
const title = this.add.text(left + menuWidth / 2, top + padding + 2, commandLabels[command], {
const title = this.add.text(left + menuWidth / 2, top + padding + 2, titleLabel, {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '16px',
fontSize: '17px',
color: '#d8b15f',
fontStyle: '700'
});
@@ -4262,40 +4360,60 @@ export class BattleScene extends Phaser.Scene {
usables.forEach((usable, index) => {
const rowTop = top + padding + titleHeight + index * rowHeight;
const bg = this.add.rectangle(left + 8, rowTop, menuWidth - 16, rowHeight - 6, 0x1a2630, 0.94);
const accent = this.usableAccentColor(usable);
const bg = this.add.rectangle(left + 8, rowTop, menuWidth - 16, rowHeight - 7, 0x1a2630, 0.95);
bg.setOrigin(0);
bg.setDepth(15);
bg.setStrokeStyle(1, command === 'strategy' ? palette.blue : palette.gold, 0.66);
bg.setStrokeStyle(1, accent, 0.68);
bg.setInteractive({ useHandCursor: true });
this.commandMenuObjects.push(bg);
const iconFrame = this.add.rectangle(left + 28, rowTop + 25, 32, 32, 0x0a0f14, 0.88);
iconFrame.setStrokeStyle(1, command === 'strategy' ? palette.blue : palette.gold, 0.58);
const iconFrame = this.add.rectangle(left + 31, rowTop + 32, 38, 38, 0x0a0f14, 0.9);
iconFrame.setStrokeStyle(1, accent, 0.66);
iconFrame.setDepth(16);
this.commandMenuObjects.push(iconFrame);
const icon = this.createBattleUiIcon(left + 28, rowTop + 25, this.usableIcon(usable), 27);
const icon = this.createBattleUiIcon(left + 31, rowTop + 32, this.usableIcon(usable), 32);
icon.setDepth(17);
this.commandMenuObjects.push(icon);
const stock = command === 'item' ? ` x${this.itemStock(unit.id, usable.id)}` : '';
const name = this.add.text(left + 50, rowTop + 7, `${usable.name}${stock}`, {
const stock = this.usableStockLabel(unit, usable);
const name = this.add.text(left + 56, rowTop + 7, usable.name, {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '16px',
fontSize: '17px',
color: '#f2e3bf',
fontStyle: '700'
});
name.setDepth(16);
this.commandMenuObjects.push(name);
const desc = this.add.text(left + 50, rowTop + 29, usable.description, {
const stockText = this.add.text(left + menuWidth - 24, rowTop + 9, stock, {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '12px',
color: '#aeb7c2',
wordWrap: { width: menuWidth - 66, useAdvancedWrap: true }
fontSize: '11px',
color: command === 'item' ? '#f4dfad' : '#9fb0bf',
fontStyle: '700'
});
desc.setDepth(16);
this.commandMenuObjects.push(desc);
stockText.setOrigin(1, 0);
stockText.setDepth(16);
this.commandMenuObjects.push(stockText);
const summary = this.add.text(
left + 56,
rowTop + 31,
`${this.usableEffectLabel(usable)} · ${this.usableTargetLabel(usable)} · 사거리 ${usable.range} · 대상 ${this.usableTargetCount(unit, usable)}`,
{
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '12px',
color: '#aeb7c2',
fixedWidth: menuWidth - 74
}
);
summary.setDepth(16);
this.commandMenuObjects.push(summary);
this.renderUsableMenuPill(left + 56, rowTop + 43, 78, this.usableIcon(usable), this.usableEffectLabel(usable), accent);
this.renderUsableMenuPill(left + 140, rowTop + 43, 86, 'move', `거리 ${usable.range}`, accent);
this.renderUsableMenuPill(left + 232, rowTop + 43, 82, usable.target === 'enemy' ? 'hit' : 'success', this.usablePowerLabel(usable), accent);
const choose = (choicePointer: Phaser.Input.Pointer) => {
if (choicePointer.rightButtonDown()) {
@@ -4308,14 +4426,12 @@ export class BattleScene extends Phaser.Scene {
};
bg.on('pointerover', () => {
bg.setFillStyle(0x283947, 0.98);
this.renderUnitDetail(unit, `${usable.name}\n${usable.description}`);
this.renderUnitDetail(unit, this.usableDetailText(unit, usable));
});
bg.on('pointerout', () => bg.setFillStyle(0x1a2630, 0.94));
bg.on('pointerdown', choose);
name.setInteractive({ useHandCursor: true });
name.on('pointerdown', choose);
desc.setInteractive({ useHandCursor: true });
desc.on('pointerdown', choose);
});
}
@@ -4535,6 +4651,7 @@ export class BattleScene extends Phaser.Scene {
private showSupportTargets(user: UnitData, usable: BattleUsable, targets = this.supportTargets(user, usable)) {
targets.forEach((target) => {
const preview = this.supportPreview(user, target, usable);
const marker = this.add.rectangle(
this.tileTopLeftX(target.x),
this.tileTopLeftY(target.y),
@@ -4573,7 +4690,7 @@ export class BattleScene extends Phaser.Scene {
hitArea.on('pointerover', () => {
marker.setFillStyle(usable.effect === 'heal' ? 0x45b875 : 0x4f86d9, 0.34);
marker.setStrokeStyle(3, usable.effect === 'heal' ? 0xd9ffe8 : 0xf2f7ff, 1);
this.renderSupportPreview(user, target, usable);
this.renderSupportPreview(preview);
});
hitArea.on('pointerout', () => {
marker.setFillStyle(usable.effect === 'heal' ? 0x45b875 : 0x4f86d9, 0.2);
@@ -4647,17 +4764,24 @@ export class BattleScene extends Phaser.Scene {
this.renderCombatPreviewCard(preview);
}
private renderSupportPreview(user: UnitData, target: UnitData, usable: BattleUsable) {
if (usable.effect === 'heal') {
const amount = this.supportHealAmount(user, target, usable);
this.renderUnitDetail(target, `${user.name} ${usable.name} 예측\n병력 +${amount} / ${target.hp} -> ${Math.min(target.maxHp, target.hp + amount)}`);
return;
}
this.renderUnitDetail(
private supportPreview(user: UnitData, target: UnitData, usable: BattleUsable): SupportPreview {
const healAmount = usable.effect === 'heal' ? this.supportHealAmount(user, target, usable) : 0;
return {
usable,
user,
target,
`${user.name} ${usable.name} 예측\n공격 +${usable.attackBonus ?? 0} / 명중 +${usable.hitBonus ?? 0} / 치명 +${usable.criticalBonus ?? 0}\n${usable.duration ?? 1}턴 동안 유지`
);
healAmount,
projectedHp: Math.min(target.maxHp, target.hp + healAmount),
attackBonus: usable.attackBonus ?? 0,
hitBonus: usable.hitBonus ?? 0,
criticalBonus: usable.criticalBonus ?? 0,
duration: usable.duration ?? 1
};
}
private renderSupportPreview(preview: SupportPreview) {
this.renderUnitDetail(preview.target);
this.renderSupportPreviewCard(preview);
}
private equipmentPreviewBonusText(preview: CombatPreview) {
@@ -4758,6 +4882,59 @@ export class BattleScene extends Phaser.Scene {
}
}
private renderSupportPreviewCard(preview: SupportPreview) {
const { panelX, panelWidth } = this.layout;
const left = panelX + 24;
const width = panelWidth - 48;
const height = 158;
const y = Math.min(this.sideContentTop() + 402, this.sideContentBottom(10) - height);
const accent = this.usableAccentColor(preview.usable);
const bg = this.trackSideObject(this.add.rectangle(left, y, width, height, 0x121a22, 0.98));
bg.setOrigin(0);
bg.setStrokeStyle(2, accent, 0.78);
const actionFrame = this.trackSideObject(this.add.rectangle(left + 24, y + 27, 42, 42, 0x0a0f14, 0.9));
actionFrame.setStrokeStyle(1, accent, 0.76);
this.trackSideIcon(left + 24, y + 27, this.usableIcon(preview.usable), 35);
this.trackSideObject(this.add.text(left + 52, y + 9, `${preview.user.name} ${preview.usable.name} 예측`, {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '16px',
color: '#f4dfad',
fontStyle: '700'
}));
this.trackSideObject(this.add.text(left + 52, y + 30, `${preview.target.name} / ${this.usableEffectLabel(preview.usable)} / ${this.usableTargetLabel(preview.usable)}`, {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '12px',
color: '#9fb0bf'
}));
const metricTop = y + 56;
const metricGap = 6;
const metricWidth = (width - 20 - metricGap * 2) / 3;
if (preview.usable.effect === 'heal') {
this.renderPreviewMetric(left + 10, metricTop, metricWidth, 'hp', '회복', `+${preview.healAmount}`, 0x59d18c);
this.renderPreviewMetric(left + 10 + metricWidth + metricGap, metricTop, metricWidth, 'success', '적용', '100%', accent);
this.renderPreviewMetric(left + 10 + (metricWidth + metricGap) * 2, metricTop, metricWidth, 'move', '거리', `${preview.usable.range}`, accent);
} else {
this.renderPreviewMetric(left + 10, metricTop, metricWidth, 'attack', '공격', `+${preview.attackBonus}`, 0xd8b15f);
this.renderPreviewMetric(left + 10 + metricWidth + metricGap, metricTop, metricWidth, 'hit', '명중', `+${preview.hitBonus}`, accent);
this.renderPreviewMetric(left + 10 + (metricWidth + metricGap) * 2, metricTop, metricWidth, 'critical', '치명', `+${preview.criticalBonus}`, 0xd8732c);
}
this.renderSupportForecastRow(preview, left + 10, y + 98, width - 20, accent);
const badgeY = y + 126;
const maxBadgeRight = left + width - 10;
let badgeX = left + 10;
badgeX = this.renderPreviewBadge(badgeX, badgeY, this.usableIcon(preview.usable), this.usableEffectLabel(preview.usable), maxBadgeRight);
badgeX = this.renderPreviewBadge(badgeX, badgeY, 'move', `사거리 ${preview.usable.range}`, maxBadgeRight);
badgeX = this.renderPreviewBadge(badgeX, badgeY, 'success', preview.usable.command === 'item' ? '도구 사용' : '책략 사용', maxBadgeRight);
if (preview.usable.effect === 'focus') {
this.renderPreviewBadge(badgeX, badgeY, 'leadership', `${preview.duration}`, maxBadgeRight);
}
}
private renderPreviewEquipmentChip(
x: number,
y: number,
@@ -4837,6 +5014,45 @@ export class BattleScene extends Phaser.Scene {
hpText.setOrigin(1, 0);
}
private renderSupportForecastRow(preview: SupportPreview, x: number, y: number, width: number, accent: number) {
const row = this.trackSideObject(this.add.rectangle(x, y, width, 22, 0x0b1118, 0.94));
row.setOrigin(0);
row.setStrokeStyle(1, accent, 0.48);
const isHeal = preview.usable.effect === 'heal';
this.trackSideIcon(x + 12, y + 11, isHeal ? 'hp' : 'leadership', 17);
this.trackSideObject(this.add.text(x + 26, y + 5, isHeal ? '적용 후 HP' : '강화 결과', {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '11px',
color: '#9fb0bf',
fontStyle: '700'
}));
if (isHeal) {
this.drawGauge(x + 100, y + 7, width - 178, 8, preview.projectedHp / preview.target.maxHp, 0x59d18c);
const hpText = this.trackSideObject(this.add.text(x + width - 8, y + 5, `${preview.target.hp} -> ${preview.projectedHp}`, {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '12px',
color: '#f2e3bf',
fontStyle: '700'
}));
hpText.setOrigin(1, 0);
return;
}
const buffText = this.trackSideObject(this.add.text(
x + width - 8,
y + 5,
`공+${preview.attackBonus} / 명+${preview.hitBonus} / 치+${preview.criticalBonus} / ${preview.duration}`,
{
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '12px',
color: '#f2e3bf',
fontStyle: '700'
}
));
buffText.setOrigin(1, 0);
}
private renderPreviewBadge(x: number, y: number, icon: BattleUiIconKey, label: string, maxRight?: number) {
const width = Phaser.Math.Clamp(label.length * 8 + 42, 68, 138);
if (maxRight && x + width > maxRight) {
@@ -7844,22 +8060,23 @@ export class BattleScene extends Phaser.Scene {
}));
title.setOrigin(0.5, 0);
title.setDepth(depth + 2);
this.renderSupportActionRibbon(result, left + panelWidth / 2 - 220, top + 58, 440, depth + 9);
const supportPose: UnitActionPose = result.usable.command === 'strategy' ? 'strategy' : 'item';
const userSprite = this.trackCombatObject(
this.add.sprite(left + 160, top + 146, this.unitActionTexture(result.user), this.unitActionFrameIndex('east', supportPose))
this.add.sprite(left + 160, top + 156, this.unitActionTexture(result.user), this.unitActionFrameIndex('east', supportPose))
);
userSprite.setDepth(depth + 3);
this.applyCombatSpriteDisplaySize(userSprite, result.user, true);
this.applyActionSpriteBlend(userSprite);
void this.playUnitActionFrames(userSprite, result.user, 'east', supportPose, 100, 2);
const targetSprite = this.trackCombatObject(this.add.sprite(left + panelWidth - 160, top + 146, this.unitTextureKey(result.target), this.unitFrameIndex('west')));
const targetSprite = this.trackCombatObject(this.add.sprite(left + panelWidth - 160, top + 156, this.unitTextureKey(result.target), this.unitFrameIndex('west')));
targetSprite.setDepth(depth + 3);
this.applyCombatSpriteDisplaySize(targetSprite, result.target, true);
const effectColor = result.usable.effect === 'heal' ? 0x59d18c : 0xd8b15f;
const effect = this.trackCombatObject(this.add.circle(left + panelWidth / 2, top + 145, 30, effectColor, 0.76));
const effect = this.trackCombatObject(this.add.circle(left + panelWidth / 2, top + 156, 30, effectColor, 0.76));
effect.setDepth(depth + 4);
this.tweens.add({ targets: effect, scale: 1.45, alpha: 0.18, duration: 520, yoyo: true });
soundDirector.playEffect(result.usable.command === 'strategy' ? 'strategy-cast' : 'exp-gain', {
@@ -7867,7 +8084,7 @@ export class BattleScene extends Phaser.Scene {
stopAfterMs: 900
});
const targetStatus = this.renderCombatStatusPanel(result.target, left + panelWidth / 2 - 196, top + 190, 392);
const targetStatus = this.renderCombatStatusPanel(result.target, left + panelWidth / 2 - 196, top + 202, 392);
targetStatus.hpFill.setScale(result.previousTargetHp / result.target.maxHp, 1);
targetStatus.hpText.setText(`${result.previousTargetHp} / ${result.target.maxHp}`);
const growthEntries = this.supportGrowthEntries(result);
@@ -7880,7 +8097,7 @@ export class BattleScene extends Phaser.Scene {
result.usable.effect === 'heal'
? `${result.target.name} 병력 +${result.healAmount}`
: `${result.target.name} ${result.usable.name}: 공격 +${result.buff?.attackBonus ?? 0} / 명중 +${result.buff?.hitBonus ?? 0} / 치명 +${result.buff?.criticalBonus ?? 0}`;
const resultText = this.trackCombatObject(this.add.text(left + panelWidth / 2, top + 106, resultLine, {
const resultText = this.trackCombatObject(this.add.text(left + panelWidth / 2, top + 132, resultLine, {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '19px',
color: result.usable.effect === 'heal' ? '#a8ffd0' : '#ffdf7b',
@@ -7890,7 +8107,7 @@ export class BattleScene extends Phaser.Scene {
}));
resultText.setOrigin(0.5);
resultText.setDepth(depth + 5);
void this.playImmediateGrowthPopups(growthEntries, left + panelWidth / 2, top + 156, depth + 8);
void this.playImmediateGrowthPopups(growthEntries, left + panelWidth / 2, top + 178, depth + 8);
await this.playGrowthRewardPanel({
x: left + 64,
@@ -7906,6 +8123,87 @@ export class BattleScene extends Phaser.Scene {
this.hideCombatCutIn();
}
private renderSupportActionRibbon(result: SupportResult, x: number, y: number, width: number, depth: number) {
const accent = this.usableAccentColor(result.usable);
const bg = this.trackCombatObject(this.add.rectangle(x, y, width, 64, 0x0b1118, 0.92));
bg.setOrigin(0);
bg.setDepth(depth);
bg.setStrokeStyle(1, accent, 0.66);
const actionFrame = this.trackCombatObject(this.add.rectangle(x + 24, y + 22, 36, 36, 0x101820, 0.9));
actionFrame.setDepth(depth + 1);
actionFrame.setStrokeStyle(1, accent, 0.68);
this.trackCombatIcon(x + 24, y + 22, this.usableIcon(result.usable), 31, depth + 2);
const sourceItem = getItem(result.usable.command === 'strategy' ? result.user.equipment.weapon.itemId : result.user.equipment.accessory.itemId);
const sourceSlot: EquipmentSlot = result.usable.command === 'strategy' ? 'weapon' : 'accessory';
const sourceFrame = this.trackCombatObject(this.add.rectangle(x + 136, y + 22, 30, 30, 0x16212d, 0.9));
sourceFrame.setDepth(depth + 1);
sourceFrame.setStrokeStyle(1, 0x647485, 0.58);
this.trackCombatIcon(x + 136, y + 22, this.itemIcon(sourceItem, sourceSlot), 25, depth + 2);
const targetFrame = this.trackCombatObject(this.add.rectangle(x + 256, y + 22, 30, 30, 0x16212d, 0.9));
targetFrame.setDepth(depth + 1);
targetFrame.setStrokeStyle(1, 0x647485, 0.58);
this.trackCombatIcon(x + 256, y + 22, result.usable.effect === 'heal' ? 'hp' : 'leadership', 25, depth + 2);
const actionLabel = this.trackCombatObject(this.add.text(x + 46, y + 9, result.usable.name, {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '15px',
color: '#f4dfad',
fontStyle: '700',
fixedWidth: 74
}));
actionLabel.setDepth(depth + 1);
const sourceLabel = this.trackCombatObject(this.add.text(x + 156, y + 7, sourceItem.name, {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '12px',
color: '#d4dce6',
fixedWidth: 90
}));
sourceLabel.setDepth(depth + 1);
const sourceRole = this.trackCombatObject(this.add.text(x + 156, y + 25, result.usable.command === 'strategy' ? '책략 도구' : '소모 도구', {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '10px',
color: '#9fb0bf',
fixedWidth: 90
}));
sourceRole.setDepth(depth + 1);
const targetLabel = this.trackCombatObject(this.add.text(x + 276, y + 7, result.target.name, {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '12px',
color: '#d4dce6',
fixedWidth: 74
}));
targetLabel.setDepth(depth + 1);
const targetRole = this.trackCombatObject(this.add.text(x + 276, y + 25, this.usableTargetLabel(result.usable), {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '10px',
color: '#9fb0bf',
fixedWidth: 74
}));
targetRole.setDepth(depth + 1);
const resultLabel =
result.usable.effect === 'heal'
? `회복 +${result.healAmount}`
: `강화 ${result.buff?.turns ?? result.usable.duration ?? 1}`;
const resultText = this.trackCombatObject(this.add.text(x + width - 14, y + 10, resultLabel, {
fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif',
fontSize: '13px',
color: result.usable.effect === 'heal' ? '#a8ffd0' : '#ffdf7b',
fontStyle: '700'
}));
resultText.setOrigin(1, 0);
resultText.setDepth(depth + 1);
this.renderCombatRibbonBadge(x + 46, y + 38, this.usableIcon(result.usable), this.usableEffectLabel(result.usable), depth + 1, 68);
this.renderCombatRibbonBadge(x + 120, y + 38, 'success', '적용', depth + 1, 58);
this.renderCombatRibbonBadge(x + 184, y + 38, 'move', `거리 ${result.usable.range}`, depth + 1, 66);
}
private renderCombatStatusPanel(unit: UnitData, x: number, y: number, width: number, growth?: CharacterGrowthResult) {
const panel = this.trackCombatObject(this.add.rectangle(x, y, width, 116, 0x101820, 0.96));
panel.setOrigin(0);