working on useScore
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
import { useGame } from "./useGame";
|
import { useGame } from "./useGame";
|
||||||
|
import { useScore } from "./useScore";
|
||||||
|
|
||||||
export type UseGameType = ReturnType<typeof useGame>;
|
export type UseGameType = ReturnType<typeof useGame>;
|
||||||
|
export type UseScoreType = ReturnType<typeof useScore>;
|
||||||
|
|
||||||
export type {
|
export type {
|
||||||
Difficulty,
|
Difficulty,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useCursor } from "./useCursor";
|
|||||||
import { useGameStatus } from "./useGameStatus";
|
import { useGameStatus } from "./useGameStatus";
|
||||||
import { useBoardState } from "./useBoardState";
|
import { useBoardState } from "./useBoardState";
|
||||||
import { useKeyBindings } from "./useKeyBindings";
|
import { useKeyBindings } from "./useKeyBindings";
|
||||||
|
import { useScore } from "../useScore";
|
||||||
|
|
||||||
export function useGame(platformHook?: unknown) {
|
export function useGame(platformHook?: unknown) {
|
||||||
const rendererManager = useRenderer();
|
const rendererManager = useRenderer();
|
||||||
@@ -15,6 +16,10 @@ export function useGame(platformHook?: unknown) {
|
|||||||
const boardManager = useBoardState(cursorManager);
|
const boardManager = useBoardState(cursorManager);
|
||||||
const { board, initialBoard, solution, setDigit, erase, reset, solveBoard } = boardManager;
|
const { board, initialBoard, solution, setDigit, erase, reset, solveBoard } = boardManager;
|
||||||
|
|
||||||
|
const scoreManager = useScore({
|
||||||
|
gameContext: { gameStatus, setGameStatus },
|
||||||
|
});
|
||||||
|
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
// Keybindings
|
// Keybindings
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
@@ -81,6 +86,9 @@ export function useGame(platformHook?: unknown) {
|
|||||||
reset,
|
reset,
|
||||||
solveBoard,
|
solveBoard,
|
||||||
|
|
||||||
|
// scoring
|
||||||
|
scoreManager,
|
||||||
|
|
||||||
// keybindings (vim-maze compatible)
|
// keybindings (vim-maze compatible)
|
||||||
...keyBindings,
|
...keyBindings,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
|
export type UseTimerReturn = {
|
||||||
|
timeValue: number;
|
||||||
|
startTimer: () => void;
|
||||||
|
stopTimer: () => void;
|
||||||
|
resetTimer: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UseTimerOptions = {
|
||||||
|
interval?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useTimer(options: UseTimerOptions = {}): UseTimerReturn {
|
||||||
|
const { interval = 100 } = options;
|
||||||
|
const [timeValue, setTimeValue] = useState(0);
|
||||||
|
|
||||||
|
const intervalIdRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
||||||
|
const offsetRef = useRef(0);
|
||||||
|
const startTimeRef = useRef<number | null>(null);
|
||||||
|
|
||||||
|
const update = useCallback(() => {
|
||||||
|
if (startTimeRef.current === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const now = performance.now();
|
||||||
|
setTimeValue(offsetRef.current + (now - startTimeRef.current));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const startTimer = useCallback(() => {
|
||||||
|
if (intervalIdRef.current !== null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startTimeRef.current === null) {
|
||||||
|
startTimeRef.current = performance.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
|
intervalIdRef.current = setInterval(update, Math.max(16, interval));
|
||||||
|
}, [interval, update]);
|
||||||
|
|
||||||
|
const stopTimer = useCallback(() => {
|
||||||
|
if (intervalIdRef.current !== null) {
|
||||||
|
clearInterval(intervalIdRef.current);
|
||||||
|
intervalIdRef.current = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startTimeRef.current !== null) {
|
||||||
|
update();
|
||||||
|
offsetRef.current += performance.now() - startTimeRef.current;
|
||||||
|
startTimeRef.current = null;
|
||||||
|
}
|
||||||
|
}, [update]);
|
||||||
|
|
||||||
|
const resetTimer = useCallback(() => {
|
||||||
|
if (intervalIdRef.current !== null) {
|
||||||
|
clearInterval(intervalIdRef.current);
|
||||||
|
intervalIdRef.current = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
startTimeRef.current = null;
|
||||||
|
offsetRef.current = 0;
|
||||||
|
setTimeValue(0);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
if (intervalIdRef.current !== null) {
|
||||||
|
clearInterval(intervalIdRef.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return {
|
||||||
|
timeValue,
|
||||||
|
startTimer,
|
||||||
|
stopTimer,
|
||||||
|
resetTimer,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { useTimer } from "./hooks/useTimer";
|
||||||
|
import { useScoreTime } from "./useScoreTime";
|
||||||
|
import type { GameStatus } from "../types";
|
||||||
|
|
||||||
|
type GameScoreContext = {
|
||||||
|
gameStatus: GameStatus;
|
||||||
|
setGameStatus: (status: GameStatus) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
type UseScoreParams = {
|
||||||
|
gameContext: GameScoreContext;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useScore({ gameContext }: UseScoreParams) {
|
||||||
|
const timer = useTimer();
|
||||||
|
const { gameStatus } = gameContext;
|
||||||
|
const { timeValue, startTimer, stopTimer, resetTimer } = timer;
|
||||||
|
|
||||||
|
const [finalScore, setFinalScore] = useState<number | null>(null);
|
||||||
|
|
||||||
|
useScoreTime({ gameStatus, timer });
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (gameStatus !== "game-won") return;
|
||||||
|
|
||||||
|
const timeInSeconds = timeValue / 1000;
|
||||||
|
const baseScore = 100000;
|
||||||
|
const timePenalty = Math.floor(timeInSeconds * 10);
|
||||||
|
const score = Math.max(0, baseScore - timePenalty);
|
||||||
|
|
||||||
|
setFinalScore(score);
|
||||||
|
}, [gameStatus, timeValue]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
timeValue,
|
||||||
|
startTimer,
|
||||||
|
stopTimer,
|
||||||
|
resetTimer,
|
||||||
|
finalScore,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UseScoreType = ReturnType<typeof useScore>;
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { useEffect, useRef } from "react";
|
||||||
|
import type { UseTimerReturn } from "./hooks/useTimer";
|
||||||
|
import type { GameStatus } from "../types";
|
||||||
|
|
||||||
|
type UseScoreTimeParams = {
|
||||||
|
gameStatus: GameStatus;
|
||||||
|
timer: UseTimerReturn;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useScoreTime({ gameStatus, timer }: UseScoreTimeParams) {
|
||||||
|
const prevStatusRef = useRef<GameStatus | null>(null);
|
||||||
|
const { startTimer, stopTimer, resetTimer } = timer;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
prevStatusRef.current = gameStatus;
|
||||||
|
|
||||||
|
switch (gameStatus) {
|
||||||
|
case "started":
|
||||||
|
resetTimer();
|
||||||
|
startTimer();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "game-over":
|
||||||
|
case "game-won":
|
||||||
|
case "waiting":
|
||||||
|
stopTimer();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}, [gameStatus, startTimer, stopTimer, resetTimer]);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user