feat: add custom gameOver condition to GameOptions
- Add optional gameOver field to GameOptions - Can be a boolean value or a function that receives scoreManager - Function receives current score metrics to make dynamic decisions - Enables flexible game-over conditions beyond just time limit - Example: gameOver: (sm) => sm.efficiency > 150 for efficiency threshold - Checked every frame during 'started' and 'has-key' states
This commit is contained in:
@@ -12,6 +12,7 @@ export type GameOptions = {
|
|||||||
rows: number;
|
rows: number;
|
||||||
cols: number;
|
cols: number;
|
||||||
timeLimit?: number;
|
timeLimit?: number;
|
||||||
|
gameOver?: boolean | ((scoreManager: ScoreManager) => boolean);
|
||||||
};
|
};
|
||||||
|
|
||||||
export type KeyLogEntry = { key: string; timestamp: number };
|
export type KeyLogEntry = { key: string; timestamp: number };
|
||||||
|
|||||||
+2
-2
@@ -6,7 +6,7 @@ import { useHeroRender } from './useCursor';
|
|||||||
import { useScore } from './useScore';
|
import { useScore } from './useScore';
|
||||||
|
|
||||||
export function useGame(options: GameOptions, platformHook?: unknown): GameManager {
|
export function useGame(options: GameOptions, platformHook?: unknown): GameManager {
|
||||||
const { cols, rows, timeLimit = 600 } = options;
|
const { cols, rows, timeLimit = 600, gameOver } = options;
|
||||||
const board = useBoard(cols, rows);
|
const board = useBoard(cols, rows);
|
||||||
const { containerRef, renderBoard } = board;
|
const { containerRef, renderBoard } = board;
|
||||||
const gameStatusManager = useGameStatus();
|
const gameStatusManager = useGameStatus();
|
||||||
@@ -14,7 +14,7 @@ export function useGame(options: GameOptions, platformHook?: unknown): GameManag
|
|||||||
|
|
||||||
const hero = cursor.hero;
|
const hero = cursor.hero;
|
||||||
const renderer = useHeroRender({ gameStatus: gameStatusManager.gameStatus, board, hero });
|
const renderer = useHeroRender({ gameStatus: gameStatusManager.gameStatus, board, hero });
|
||||||
const scoreManager = useScore({ board, hero, gameStatusManager, keyManager, rows, cols, timeLimit });
|
const scoreManager = useScore({ board, hero, gameStatusManager, keyManager, rows, cols, timeLimit, gameOver });
|
||||||
|
|
||||||
const gameManager: GameManager = {
|
const gameManager: GameManager = {
|
||||||
containerRef,
|
containerRef,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { useScorePaths } from "./useScorePaths";
|
|||||||
import type { BoardManager } from "../useBoard/types";
|
import type { BoardManager } from "../useBoard/types";
|
||||||
import type { GameStatusManager } from "../useGameStatus/types";
|
import type { GameStatusManager } from "../useGameStatus/types";
|
||||||
import type { UseHeroType } from "../useCursor/types";
|
import type { UseHeroType } from "../useCursor/types";
|
||||||
|
import type { ScoreManager } from "./types";
|
||||||
|
|
||||||
type UseScoreParams = {
|
type UseScoreParams = {
|
||||||
board: BoardManager;
|
board: BoardManager;
|
||||||
@@ -14,9 +15,10 @@ type UseScoreParams = {
|
|||||||
rows: number;
|
rows: number;
|
||||||
cols: number;
|
cols: number;
|
||||||
timeLimit: number;
|
timeLimit: number;
|
||||||
|
gameOver?: boolean | ((scoreManager: ScoreManager) => boolean);
|
||||||
};
|
};
|
||||||
|
|
||||||
export function useScore({ board, hero, gameStatusManager, keyManager, rows, cols, timeLimit }: UseScoreParams) {
|
export function useScore({ board, hero, gameStatusManager, keyManager, rows, cols, timeLimit, gameOver }: UseScoreParams) {
|
||||||
const timer = useTimer();
|
const timer = useTimer();
|
||||||
const { gameStatus, setGameStatus } = gameStatusManager;
|
const { gameStatus, setGameStatus } = gameStatusManager;
|
||||||
const { timeValue, startTimer, stopTimer, resetTimer } = timer;
|
const { timeValue, startTimer, stopTimer, resetTimer } = timer;
|
||||||
@@ -64,6 +66,30 @@ export function useScore({ board, hero, gameStatusManager, keyManager, rows, col
|
|||||||
}
|
}
|
||||||
}, [gameStatus, timeValue, timeLimit, setGameStatus]);
|
}, [gameStatus, timeValue, timeLimit, setGameStatus]);
|
||||||
|
|
||||||
|
// Check custom gameOver condition if provided
|
||||||
|
useEffect(() => {
|
||||||
|
if (gameStatus !== "started" && gameStatus !== "has-key") return;
|
||||||
|
if (!gameOver) return;
|
||||||
|
|
||||||
|
const scoreManager = {
|
||||||
|
timeValue,
|
||||||
|
startTimer,
|
||||||
|
stopTimer,
|
||||||
|
resetTimer,
|
||||||
|
distToKey,
|
||||||
|
distToExit,
|
||||||
|
keystrokes,
|
||||||
|
optimalSteps,
|
||||||
|
efficiency,
|
||||||
|
finalScore,
|
||||||
|
};
|
||||||
|
|
||||||
|
const shouldGameOver = typeof gameOver === "function" ? gameOver(scoreManager) : gameOver;
|
||||||
|
if (shouldGameOver) {
|
||||||
|
setGameStatus("game-over");
|
||||||
|
}
|
||||||
|
}, [gameStatus, gameOver, timeValue, keystrokes, optimalSteps, efficiency, distToKey, distToExit, startTimer, stopTimer, resetTimer, finalScore, setGameStatus]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (gameStatus !== "game-won") return;
|
if (gameStatus !== "game-won") return;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user