Update 3D game 2026-07-10 21:20
This commit is contained in:
+73
@@ -0,0 +1,73 @@
|
||||
import { lazy, Suspense, useCallback, useEffect, useRef } from "react";
|
||||
import { DualDisplayFrame } from "./components/DualDisplayFrame";
|
||||
import { FrontEnd } from "./components/FrontEnd";
|
||||
import { useActiveHunter, useFrontendStore } from "./frontend/store";
|
||||
import { useGameStore } from "./game/store";
|
||||
import type { BossId } from "./game/types";
|
||||
import { useActionBindings, useGameLoop } from "./game/useGameLoop";
|
||||
|
||||
const TopScreen = lazy(() => import("./components/TopScreen").then((module) => ({ default: module.TopScreen })));
|
||||
const BottomScreen = lazy(() => import("./components/BottomScreen").then((module) => ({ default: module.BottomScreen })));
|
||||
|
||||
function GameLoadingScreen() {
|
||||
return (
|
||||
<DualDisplayFrame
|
||||
top={<section className="display top-display game-loading"><span>✦</span><strong>Opening the Ember Vault</strong><small>Preparing world and party…</small></section>}
|
||||
bottom={<section className="display bottom-display game-loading is-lower"><span>IH</span><strong>Loading field console</strong><small>Offline save secured</small></section>}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
useGameLoop();
|
||||
const screen = useFrontendStore((state) => state.screen);
|
||||
const hunter = useActiveHunter();
|
||||
const settings = useFrontendStore((state) => state.settings);
|
||||
const navigate = useFrontendStore((state) => state.navigate);
|
||||
const touchActiveSave = useFrontendStore((state) => state.touchActiveSave);
|
||||
const updateActiveHealerInventory = useFrontendStore((state) => state.updateActiveHealerInventory);
|
||||
const recordBossVictory = useFrontendStore((state) => state.recordBossVictory);
|
||||
const phase = useGameStore((state) => state.phase);
|
||||
const boss = useGameStore((state) => state.boss);
|
||||
const additionalBosses = useGameStore((state) => state.additionalBosses);
|
||||
const victoryRecorded = useRef(false);
|
||||
const leaveGame = useCallback(() => {
|
||||
updateActiveHealerInventory(useGameStore.getState().inventory);
|
||||
touchActiveSave();
|
||||
navigate("home");
|
||||
}, [navigate, touchActiveSave, updateActiveHealerInventory]);
|
||||
const launchGame = useCallback((bossIds: readonly BossId[]) => {
|
||||
if (!hunter) return;
|
||||
const progress = hunter.healers[hunter.activeClassId];
|
||||
useGameStore.getState().configureHealer(hunter.activeClassId, hunter.hunterName, progress.inventory, bossIds);
|
||||
touchActiveSave();
|
||||
navigate("game");
|
||||
}, [hunter, navigate, touchActiveSave]);
|
||||
|
||||
useActionBindings(screen === "game", leaveGame);
|
||||
|
||||
useEffect(() => {
|
||||
document.documentElement.classList.toggle("large-interface-text", settings.largeText);
|
||||
document.documentElement.classList.toggle("force-reduced-motion", settings.reducedMotion);
|
||||
}, [settings.largeText, settings.reducedMotion]);
|
||||
|
||||
useEffect(() => {
|
||||
if (phase === "combat") victoryRecorded.current = false;
|
||||
if (screen === "game" && phase === "victory" && !victoryRecorded.current) {
|
||||
victoryRecorded.current = true;
|
||||
for (const bossName of [boss.name, ...additionalBosses.map((entry) => entry.boss.name)]) recordBossVictory(bossName);
|
||||
}
|
||||
}, [additionalBosses, boss.name, phase, recordBossVictory, screen]);
|
||||
|
||||
return (
|
||||
<main className="prototype-shell">
|
||||
<header className="prototype-header">
|
||||
<div><span>THOR / DUAL DISPLAY</span><strong>I Want To Heal</strong></div>
|
||||
<p>Offline-first healer roguelike <i /> build 0.2</p>
|
||||
</header>
|
||||
{screen === "game"
|
||||
? <Suspense fallback={<GameLoadingScreen />}><DualDisplayFrame top={<TopScreen onExit={leaveGame} />} bottom={<BottomScreen />} /></Suspense>
|
||||
: <FrontEnd onLaunch={launchGame} />}
|
||||
</main>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user