221 lines
5.8 KiB
JavaScript
221 lines
5.8 KiB
JavaScript
import Phaser from "phaser";
|
|
import { ArenaScene } from "./game/arena/ArenaScene.js";
|
|
import {
|
|
ARENA_SIZE,
|
|
PRESENTATION_TEAM_COUNT,
|
|
PRESENTATION_TEAM_SIZE,
|
|
} from "./constants.js";
|
|
import { createMatchForm } from "./ui/matchForm.js";
|
|
import { createAboutDialog } from "./ui/aboutDialog.js";
|
|
import { trackVisitor } from "./ui/visitorCounter.js";
|
|
|
|
const matchForm = createMatchForm();
|
|
const aboutDialog = createAboutDialog();
|
|
const appNode = document.querySelector("#app");
|
|
const startButton = document.querySelector("#start-button");
|
|
const drawer = document.querySelector("#fighter-entry");
|
|
const drawerCloseButton = document.querySelector("#drawer-close");
|
|
const drawerScrim = document.querySelector("#drawer-scrim");
|
|
const drawerToggleButton = document.querySelector("#drawer-toggle");
|
|
const playerNamesInput = document.querySelector("#player-names");
|
|
const pauseButton = document.querySelector("#pause-button");
|
|
const restartButton = document.querySelector("#restart-button");
|
|
const MOBILE_MATCH_MEDIA_QUERY = "(max-width: 960px)";
|
|
|
|
function isMatchLive() {
|
|
return appNode?.classList.contains("match-live") ?? false;
|
|
}
|
|
|
|
function openOptionsDrawer({ focus = true } = {}) {
|
|
appNode?.classList.add("options-open");
|
|
setDrawerCollapsed(false);
|
|
resetDrawerScroll();
|
|
drawer?.setAttribute("aria-hidden", "false");
|
|
startButton?.setAttribute("aria-expanded", "true");
|
|
|
|
if (focus) {
|
|
window.setTimeout(() => playerNamesInput?.focus(), 220);
|
|
}
|
|
}
|
|
|
|
function closeOptionsDrawer() {
|
|
if (isMatchLive()) {
|
|
setDrawerCollapsed(true);
|
|
return;
|
|
}
|
|
|
|
appNode?.classList.remove("options-open");
|
|
appNode?.classList.remove("drawer-collapsed");
|
|
drawer?.setAttribute("aria-hidden", "true");
|
|
startButton?.setAttribute("aria-expanded", "false");
|
|
syncDrawerToggleButton();
|
|
}
|
|
|
|
function startConfiguredMatch(matchConfig) {
|
|
if (matchConfig.names.length < 2) {
|
|
matchForm.setStatus("참가자 닉네임을 2명 이상 입력하세요");
|
|
return;
|
|
}
|
|
|
|
appNode?.classList.remove("match-ended");
|
|
appNode?.classList.add("match-live");
|
|
|
|
if (shouldCompactOptionsDrawer()) {
|
|
setDrawerCollapsed(true);
|
|
} else {
|
|
openOptionsDrawer({ focus: false });
|
|
}
|
|
|
|
arenaScene.startMatch(matchConfig);
|
|
syncPauseButton();
|
|
}
|
|
|
|
function getPresentationMatchConfig() {
|
|
return {
|
|
names: Array.from({ length: PRESENTATION_TEAM_COUNT }, (_, index) => `Player ${index + 1}`),
|
|
teamSize: PRESENTATION_TEAM_SIZE,
|
|
};
|
|
}
|
|
|
|
function setDrawerCollapsed(collapsed) {
|
|
const nextCollapsed = Boolean(collapsed) && isMatchLive();
|
|
|
|
appNode?.classList.toggle("drawer-collapsed", nextCollapsed);
|
|
drawer?.setAttribute("aria-hidden", "false");
|
|
|
|
if (!nextCollapsed) {
|
|
resetDrawerScroll();
|
|
}
|
|
|
|
syncDrawerToggleButton();
|
|
}
|
|
|
|
function syncDrawerToggleButton() {
|
|
if (!drawerToggleButton) {
|
|
return;
|
|
}
|
|
|
|
const isCollapsed = appNode?.classList.contains("drawer-collapsed") ?? false;
|
|
drawerToggleButton.textContent = isCollapsed ? "옵션 펼치기" : "옵션 접기";
|
|
drawerToggleButton.setAttribute("aria-expanded", String(!isCollapsed));
|
|
}
|
|
|
|
function syncPauseButton() {
|
|
if (!pauseButton) {
|
|
return;
|
|
}
|
|
|
|
const isPaused = arenaScene.isMatchPaused();
|
|
appNode?.classList.toggle("match-paused", isPaused);
|
|
pauseButton.textContent = isPaused ? "계속" : "일시정지";
|
|
pauseButton.setAttribute("aria-pressed", String(isPaused));
|
|
}
|
|
|
|
function shouldCompactOptionsDrawer() {
|
|
return window.matchMedia?.(MOBILE_MATCH_MEDIA_QUERY).matches ?? window.innerWidth <= 960;
|
|
}
|
|
|
|
function resetDrawerScroll() {
|
|
if (drawer) {
|
|
drawer.scrollTop = 0;
|
|
}
|
|
}
|
|
|
|
function handleMatchEnd() {
|
|
appNode?.classList.add("match-ended");
|
|
setDrawerCollapsed(true);
|
|
syncPauseButton();
|
|
}
|
|
|
|
function revealAppWhenStylesAreReady() {
|
|
const stylesheet = document.querySelector('link[data-app-styles], link[rel="stylesheet"]');
|
|
const reveal = () => {
|
|
window.requestAnimationFrame(() => {
|
|
document.documentElement.classList.remove("app-booting");
|
|
});
|
|
};
|
|
|
|
if (!stylesheet || stylesheet.sheet) {
|
|
reveal();
|
|
return;
|
|
}
|
|
|
|
stylesheet.addEventListener("load", reveal, { once: true });
|
|
}
|
|
|
|
startButton?.addEventListener("click", openOptionsDrawer);
|
|
drawerCloseButton?.addEventListener("click", closeOptionsDrawer);
|
|
drawerScrim?.addEventListener("click", closeOptionsDrawer);
|
|
drawerToggleButton?.addEventListener("click", () => {
|
|
const isCollapsed = appNode?.classList.contains("drawer-collapsed") ?? false;
|
|
setDrawerCollapsed(!isCollapsed);
|
|
});
|
|
pauseButton?.addEventListener("click", () => {
|
|
arenaScene.togglePause();
|
|
syncPauseButton();
|
|
});
|
|
restartButton?.addEventListener("click", () => {
|
|
startConfiguredMatch(matchForm.readMatchConfig());
|
|
});
|
|
window.addEventListener("keydown", (event) => {
|
|
if (event.key === "Escape") {
|
|
if (aboutDialog?.isOpen()) {
|
|
return;
|
|
}
|
|
|
|
closeOptionsDrawer();
|
|
}
|
|
});
|
|
|
|
const arenaScene = new ArenaScene({
|
|
getInitialMatchConfig: getPresentationMatchConfig,
|
|
onMatchEnd: handleMatchEnd,
|
|
setStatus: matchForm.setStatus,
|
|
});
|
|
|
|
const game = new Phaser.Game({
|
|
type: Phaser.AUTO,
|
|
parent: "game",
|
|
width: ARENA_SIZE,
|
|
height: ARENA_SIZE,
|
|
pixelArt: true,
|
|
backgroundColor: "#282819",
|
|
physics: {
|
|
default: "arcade",
|
|
arcade: {
|
|
debug: false,
|
|
},
|
|
},
|
|
scale: {
|
|
mode: Phaser.Scale.FIT,
|
|
autoCenter: Phaser.Scale.CENTER_BOTH,
|
|
},
|
|
scene: arenaScene,
|
|
});
|
|
|
|
revealAppWhenStylesAreReady();
|
|
|
|
matchForm.onSubmit((matchConfig) => {
|
|
startConfiguredMatch(matchConfig);
|
|
});
|
|
|
|
const visitorCountNode = document.querySelector("#visitor-count");
|
|
|
|
trackVisitor({
|
|
onUpdate({ uniqueVisitors }) {
|
|
if (visitorCountNode) {
|
|
visitorCountNode.textContent = `방문자 ${uniqueVisitors.toLocaleString("ko-KR")}`;
|
|
}
|
|
},
|
|
onError(error) {
|
|
console.warn(error);
|
|
|
|
if (visitorCountNode) {
|
|
visitorCountNode.textContent = "";
|
|
visitorCountNode.hidden = true;
|
|
}
|
|
},
|
|
});
|
|
|
|
window.arenaGame = game;
|