useHeroRender

This commit is contained in:
2025-10-19 02:30:50 +01:00
parent f302c67778
commit 310355104a
4 changed files with 82 additions and 5 deletions
+5 -3
View File
@@ -1,18 +1,20 @@
import type { GameManager, GameOptions } from './types';
import { useBoard } from './useBoard';
import { useCursor } from './useCursor';
import { useHeroRender } from './useHero';
import { useKeyBindings } from './useKeyBindings';
import { useGameStatus } from './useGameStatus';
export function useGame(options: GameOptions, platformHook?: unknown): GameManager {
const { cols, rows } = options;
const boardManager = useBoard(cols, rows);
const { containerRef, renderBoard } = boardManager;
const cursor = useCursor(boardManager);
const board = useBoard(cols, rows);
const { containerRef, renderBoard } = board;
const cursor = useCursor(board);
const gameStatusManager = useGameStatus();
const { gameStatus, startGame, togglePause, quitGame } = gameStatusManager;
useHeroRender({ gameStatus, board, cursor });
const keyManager = useKeyBindings({ cursor, gameStatus });
const gameManager = {
+1
View File
@@ -0,0 +1 @@
export * from './useHeroRender';
+74
View File
@@ -0,0 +1,74 @@
import { useEffect } from "react";
import type { BoardManager, Cursor, GameStatus } from "../types";
type UseHeroRenderParams = {
gameStatus: GameStatus;
board: BoardManager;
cursor: Cursor;
relative?: boolean;
};
export function useHeroRender(params: UseHeroRenderParams) {
const { gameStatus, board, cursor, relative = true } = params;
const { containerRef } = board;
const playerPos = cursor.position();
const applyRelativeNumbers = (mazeDiv: HTMLElement, R: number, C: number) => {
const rows = Number(mazeDiv.dataset.rows || 0);
const cols = Number(mazeDiv.dataset.cols || 0);
const rowNums = mazeDiv.querySelectorAll<HTMLElement>(".number.row[data-r]");
rowNums.forEach((el) => {
const r = Number(el.getAttribute("data-r"));
if (r <= 0 || r >= rows) {
el.textContent = "";
el.classList.remove("is-active");
return;
}
el.textContent = r === R ? String(r) : String(Math.abs(r - R));
el.classList.toggle("is-active", r === R);
});
const colNums = mazeDiv.querySelectorAll<HTMLElement>(".number.col[data-c]");
colNums.forEach((el) => {
const c = Number(el.getAttribute("data-c"));
if (c <= 0 || c >= cols) {
el.textContent = "";
el.classList.remove("is-active");
return;
}
el.textContent = c === C ? String(c) : String(Math.abs(c - C));
el.classList.toggle("is-active", c === C);
});
mazeDiv.classList.add("is-relative");
};
useEffect(() => {
console.log('gameStatus', gameStatus);
const container = containerRef.current;
if (!['started', 'has-key'].includes(gameStatus)) return;
if (!container) return;
const mazeDiv = container.querySelector("#maze") as HTMLElement | null;
if (!mazeDiv) return;
mazeDiv.querySelectorAll(".hero").forEach((el) => el.classList.remove("hero"));
const selector = `.maze-row > div[data-r="${playerPos.row}"][data-c="${playerPos.col}"]`;
const cell = mazeDiv.querySelector(selector) as HTMLElement | null;
if (cell) cell.classList.add("hero");
if (relative) {
mazeDiv.dataset.rows = String(mazeDiv.querySelectorAll(".maze-row").length);
mazeDiv.dataset.cols = String(
mazeDiv
.querySelector(".maze-row > div[data-r][data-c]")
?.parentElement?.querySelectorAll(':scope > div[data-r][data-c]').length || 0
);
applyRelativeNumbers(mazeDiv, playerPos.row, playerPos.col);
}
}, [gameStatus, playerPos, containerRef, relative]);
}
export type UseHeroRenderType = ReturnType<typeof useHeroRender>;
+2 -2
View File
@@ -56,7 +56,7 @@ export const useKeyBindings = ({ cursor, gameStatus }: UseKeyBindingsParams) =>
return;
}
const isDigit = ev.key >= "0" && e.key <= "9";
const isDigit = ev.key >= "0" && ev.key <= "9";
if (isDigit) {
if (ev.key === "0" && cursor.getCount() === "") return;
recordKey(ev.key);
@@ -71,7 +71,7 @@ export const useKeyBindings = ({ cursor, gameStatus }: UseKeyBindingsParams) =>
}
if (ev.key === "^" || ev.key === "$") {
recordKey(e.key);
recordKey(ev.key);
cursor.resetCount();
if (ev.key === "^") {
cursor.moveToStart();