feat: improve battle notice system with expanded content, centralized constants, and fixed text wrapping
This commit is contained in:
parent
1668e3c941
commit
ddccd01eb6
|
|
@ -164,6 +164,10 @@ export const UI = {
|
||||||
SELECTED_FIGHTER_OUTLINE_GREEN: 228,
|
SELECTED_FIGHTER_OUTLINE_GREEN: 228,
|
||||||
SELECTED_FIGHTER_OUTLINE_BLUE: 64,
|
SELECTED_FIGHTER_OUTLINE_BLUE: 64,
|
||||||
SELECTED_FIGHTER_OUTLINE_ALPHA: 0.65,
|
SELECTED_FIGHTER_OUTLINE_ALPHA: 0.65,
|
||||||
|
// 상단 종족별 사망 통계 공지 설정
|
||||||
|
BATTLE_NOTICE_DELAY_MS: 5000,
|
||||||
|
BATTLE_NOTICE_VISIBLE_MS: 2000,
|
||||||
|
BATTLE_NOTICE_INTERVAL_MS: 10000,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 9. TEAM 도메인
|
// 9. TEAM 도메인
|
||||||
|
|
|
||||||
|
|
@ -51,9 +51,6 @@ import {
|
||||||
import { updateScoreboard } from "../../ui/arenaScoreboard.js";
|
import { updateScoreboard } from "../../ui/arenaScoreboard.js";
|
||||||
import { appendKillLog, resetKillLog } from "../../ui/arenaKillLog.js";
|
import { appendKillLog, resetKillLog } from "../../ui/arenaKillLog.js";
|
||||||
import {
|
import {
|
||||||
BATTLE_NOTICE_DELAY_MS,
|
|
||||||
BATTLE_NOTICE_INTERVAL_MS,
|
|
||||||
BATTLE_NOTICE_VISIBLE_MS,
|
|
||||||
clearBattleNotice,
|
clearBattleNotice,
|
||||||
showBattleDeathNotice,
|
showBattleDeathNotice,
|
||||||
} from "../../ui/battleDeathNotice.js";
|
} from "../../ui/battleDeathNotice.js";
|
||||||
|
|
@ -295,7 +292,7 @@ export class ArenaScene extends Phaser.Scene {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduleBattleNotice(delayMs = BATTLE_NOTICE_DELAY_MS) {
|
scheduleBattleNotice(delayMs = UI.BATTLE_NOTICE_DELAY_MS) {
|
||||||
this.battleNoticeTimer?.remove(false);
|
this.battleNoticeTimer?.remove(false);
|
||||||
this.battleNoticeTimer = this.time.delayedCall(delayMs, () => {
|
this.battleNoticeTimer = this.time.delayedCall(delayMs, () => {
|
||||||
this.battleNoticeTimer = null;
|
this.battleNoticeTimer = null;
|
||||||
|
|
@ -339,12 +336,12 @@ export class ArenaScene extends Phaser.Scene {
|
||||||
showBattleDeathNotice(noticeNode, message);
|
showBattleDeathNotice(noticeNode, message);
|
||||||
|
|
||||||
this.battleNoticeHideTimer?.remove(false);
|
this.battleNoticeHideTimer?.remove(false);
|
||||||
this.battleNoticeHideTimer = this.time.delayedCall(BATTLE_NOTICE_VISIBLE_MS, () => {
|
this.battleNoticeHideTimer = this.time.delayedCall(UI.BATTLE_NOTICE_VISIBLE_MS, () => {
|
||||||
this.battleNoticeHideTimer = null;
|
this.battleNoticeHideTimer = null;
|
||||||
clearBattleNotice(noticeNode);
|
clearBattleNotice(noticeNode);
|
||||||
|
|
||||||
if (!this.matchOver && !this.presentationMode) {
|
if (!this.matchOver && !this.presentationMode) {
|
||||||
this.scheduleBattleNotice(BATTLE_NOTICE_INTERVAL_MS);
|
this.scheduleBattleNotice(UI.BATTLE_NOTICE_INTERVAL_MS);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -124,11 +124,12 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: min(420px, 72vmin, calc(100vw - 64px));
|
width: auto;
|
||||||
|
max-width: min(640px, calc(100vw - 40px));
|
||||||
min-height: 38px;
|
min-height: 38px;
|
||||||
border: 1px solid rgb(238 185 73 / 0.26);
|
border: 1px solid rgb(238 185 73 / 0.26);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 8px 14px;
|
padding: 8px 18px;
|
||||||
background: rgb(8 10 7 / 0.68);
|
background: rgb(8 10 7 / 0.68);
|
||||||
color: #ffe8b4;
|
color: #ffe8b4;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
|
|
@ -136,6 +137,7 @@
|
||||||
line-height: 1.35;
|
line-height: 1.35;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
text-shadow: 1px 1px 2px #000;
|
text-shadow: 1px 1px 2px #000;
|
||||||
|
white-space: nowrap;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
transform: translate(-50%, -10px);
|
transform: translate(-50%, -10px);
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { UI } from "../constants.js";
|
||||||
|
|
||||||
const SPECIES_KEYS = ["human", "orc", "skeleton", "slime", "wolf", "bear"];
|
const SPECIES_KEYS = ["human", "orc", "skeleton", "slime", "wolf", "bear"];
|
||||||
const SPECIES_LABELS = {
|
const SPECIES_LABELS = {
|
||||||
bear: "곰",
|
bear: "곰",
|
||||||
|
|
@ -22,9 +24,12 @@ const DEATH_NOTICE_TEMPLATES = [
|
||||||
"{species}{particle} 전투 중 {count}명 쓰러졌습니다. 관중석은 침착한 척하는 중입니다.",
|
"{species}{particle} 전투 중 {count}명 쓰러졌습니다. 관중석은 침착한 척하는 중입니다.",
|
||||||
];
|
];
|
||||||
|
|
||||||
export const BATTLE_NOTICE_DELAY_MS = 5000;
|
const SYSTEM_TIP_TEMPLATES = [
|
||||||
export const BATTLE_NOTICE_VISIBLE_MS = 2000;
|
"경보: 화염 메테오는 낙하 지점 5x5 영역에 강력한 폭발 피해를 입힙니다!",
|
||||||
export const BATTLE_NOTICE_INTERVAL_MS = 10000;
|
"주의: 냉기 메테오는 피해와 함께 2초간 동결 및 냉각을 유발합니다.",
|
||||||
|
"팁: 근접 캐릭터는 20% 확률로 치명타를 터뜨려 적을 즉사시킵니다.",
|
||||||
|
"성장: 적 처치 시 체력을 30% 회복하며, 크기와 속도가 최대 5배까지 커집니다.",
|
||||||
|
];
|
||||||
|
|
||||||
export function createDeathCounts() {
|
export function createDeathCounts() {
|
||||||
return SPECIES_KEYS.reduce((counts, species) => {
|
return SPECIES_KEYS.reduce((counts, species) => {
|
||||||
|
|
@ -42,7 +47,8 @@ export function normalizeDeathCounts(value = {}) {
|
||||||
|
|
||||||
export function addDeathCounts(baseCounts, matchCounts) {
|
export function addDeathCounts(baseCounts, matchCounts) {
|
||||||
return SPECIES_KEYS.reduce((counts, species) => {
|
return SPECIES_KEYS.reduce((counts, species) => {
|
||||||
counts[species] = (baseCounts?.[species] ?? 0) + (matchCounts?.[species] ?? 0);
|
counts[species] =
|
||||||
|
(baseCounts?.[species] ?? 0) + (matchCounts?.[species] ?? 0);
|
||||||
return counts;
|
return counts;
|
||||||
}, {});
|
}, {});
|
||||||
}
|
}
|
||||||
|
|
@ -52,17 +58,26 @@ export function normalizeSpecies(value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createDeathNoticeMessage(deathsBySpecies, seed = 0) {
|
export function createDeathNoticeMessage(deathsBySpecies, seed = 0) {
|
||||||
const topSpecies = SPECIES_KEYS
|
// 3번에 한 번꼴로 시스템 팁 출력
|
||||||
.map((species) => ({ species, count: deathsBySpecies?.[species] ?? 0 }))
|
if (seed % 3 === 0) {
|
||||||
.sort((left, right) => right.count - left.count)[0];
|
return SYSTEM_TIP_TEMPLATES[
|
||||||
|
Math.floor(seed / 3) % SYSTEM_TIP_TEMPLATES.length
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
const topSpecies = SPECIES_KEYS.map((species) => ({
|
||||||
|
species,
|
||||||
|
count: deathsBySpecies?.[species] ?? 0,
|
||||||
|
})).sort((left, right) => right.count - left.count)[0];
|
||||||
|
|
||||||
if (!topSpecies || topSpecies.count === 0) {
|
if (!topSpecies || topSpecies.count === 0) {
|
||||||
return "오늘 사망자 집계는 아직 0명입니다. 이 평화가 얼마나 버틸까요?";
|
return "오늘 사망자 집계는 아직 0명입니다. 이 평화가 얼마나 버틸까요?";
|
||||||
}
|
}
|
||||||
|
|
||||||
const template = DEATH_NOTICE_TEMPLATES[
|
const template =
|
||||||
(topSpecies.count + seed) % DEATH_NOTICE_TEMPLATES.length
|
DEATH_NOTICE_TEMPLATES[
|
||||||
];
|
(topSpecies.count + seed) % DEATH_NOTICE_TEMPLATES.length
|
||||||
|
];
|
||||||
|
|
||||||
return template
|
return template
|
||||||
.replace("{species}", SPECIES_LABELS[topSpecies.species])
|
.replace("{species}", SPECIES_LABELS[topSpecies.species])
|
||||||
|
|
|
||||||
5
todo.md
5
todo.md
|
|
@ -260,4 +260,9 @@
|
||||||
- 새로운 CSS 모듈 구조와 디자인 원칙을 설명하는 `context/style.md` 문서를 신규 생성.
|
- 새로운 CSS 모듈 구조와 디자인 원칙을 설명하는 `context/style.md` 문서를 신규 생성.
|
||||||
- `agent.md`의 상세 기술 가이드(Context Routing) 섹션에 스타일 및 디자인 항목을 추가하여 문서 접근성 개선.
|
- `agent.md`의 상세 기술 가이드(Context Routing) 섹션에 스타일 및 디자인 항목을 추가하여 문서 접근성 개선.
|
||||||
|
|
||||||
|
42. 상단 공지(Battle Notice) 콘텐츠 확장 (완료)
|
||||||
|
- **조치 사항**:
|
||||||
|
- 사망 통계만 보여주던 공지 UI에 게임 시스템 가이드(화염/냉기 메테오 특성, 밀리 치명타 확률 등) 팁을 추가.
|
||||||
|
- 사망 통계 공지 2회당 1회의 비율로 시스템 팁이 교차 출력되도록 로직 개선.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue