feat: add initialSnakeSize and initialFoodCount to GameOptions
- New option: initialSnakeSize (defaults to 3)
- New option: initialFoodCount (defaults to 1)
- Snake spawns with configurable size
- Initial food count is configurable
- Example: useGame({ initialSnakeSize: 5, initialFoodCount: 2 })
This commit is contained in:
@@ -35,6 +35,8 @@ export type GameOptions = {
|
|||||||
startingLevel?: number;
|
startingLevel?: number;
|
||||||
foodsPerLevel?: number;
|
foodsPerLevel?: number;
|
||||||
maxLevel?: number;
|
maxLevel?: number;
|
||||||
|
initialSnakeSize?: number;
|
||||||
|
initialFoodCount?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
@@ -2,11 +2,17 @@ import { useRef, useState } from "react";
|
|||||||
import type { Direction, SnakeBody, Position } from "../types";
|
import type { Direction, SnakeBody, Position } from "../types";
|
||||||
import type { UseBoardType } from "../useBoard";
|
import type { UseBoardType } from "../useBoard";
|
||||||
|
|
||||||
|
export type UseCursorParams = {
|
||||||
|
initialSnakeSize?: number;
|
||||||
|
};
|
||||||
|
|
||||||
export function useCursor(
|
export function useCursor(
|
||||||
cols: number,
|
cols: number,
|
||||||
rows: number,
|
rows: number,
|
||||||
boardManager: UseBoardType
|
boardManager: UseBoardType,
|
||||||
|
params?: UseCursorParams
|
||||||
) {
|
) {
|
||||||
|
const initialSnakeSize = params?.initialSnakeSize ?? 3;
|
||||||
const { containerRef } = boardManager;
|
const { containerRef } = boardManager;
|
||||||
const [snakeBody, setSnakeBody] = useState<SnakeBody>([]);
|
const [snakeBody, setSnakeBody] = useState<SnakeBody>([]);
|
||||||
const snakeBodyRef = useRef<SnakeBody>([]);
|
const snakeBodyRef = useRef<SnakeBody>([]);
|
||||||
@@ -19,11 +25,10 @@ export function useCursor(
|
|||||||
const centerR = Math.floor(rows / 2);
|
const centerR = Math.floor(rows / 2);
|
||||||
const centerC = Math.floor(cols / 2);
|
const centerC = Math.floor(cols / 2);
|
||||||
|
|
||||||
const initialBody: SnakeBody = [
|
const initialBody: SnakeBody = [];
|
||||||
{ r: centerR, c: centerC },
|
for (let i = 0; i < initialSnakeSize; i++) {
|
||||||
{ r: centerR + 1, c: centerC },
|
initialBody.push({ r: centerR + i, c: centerC });
|
||||||
{ r: centerR + 2, c: centerC },
|
}
|
||||||
];
|
|
||||||
|
|
||||||
setSnakeBody(initialBody);
|
setSnakeBody(initialBody);
|
||||||
snakeBodyRef.current = initialBody;
|
snakeBodyRef.current = initialBody;
|
||||||
|
|||||||
@@ -8,17 +8,17 @@ import { useKeyBindings, type UseKeyBindingsType } from "./useKeyBindings";
|
|||||||
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 = 30, rows = 20, startingLevel, foodsPerLevel, maxLevel } = options ?? {};
|
const { cols = 30, rows = 20, startingLevel, foodsPerLevel, maxLevel, initialSnakeSize, initialFoodCount } = options ?? {};
|
||||||
|
|
||||||
const boardManager = useBoard();
|
const boardManager = useBoard();
|
||||||
const { containerRef, renderBoard } = boardManager;
|
const { containerRef, renderBoard } = boardManager;
|
||||||
|
|
||||||
const snakeManager = useCursor(cols, rows, boardManager);
|
const snakeManager = useCursor(cols, rows, boardManager, { initialSnakeSize });
|
||||||
const { changeDirection } = snakeManager;
|
const { changeDirection } = snakeManager;
|
||||||
|
|
||||||
const foodManager = useFood(cols, rows, boardManager);
|
const foodManager = useFood(cols, rows, boardManager);
|
||||||
|
|
||||||
const gameManager = useGameStatus(boardManager, snakeManager, foodManager, { startingLevel, foodsPerLevel, maxLevel });
|
const gameManager = useGameStatus(boardManager, snakeManager, foodManager, { startingLevel, foodsPerLevel, maxLevel, initialFoodCount });
|
||||||
const { gameStatus, setGameStatus, startGame, quitGame, togglePause, score, level } = gameManager;
|
const { gameStatus, setGameStatus, startGame, quitGame, togglePause, score, level } = gameManager;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export type UseGameStatusParams = {
|
|||||||
startingLevel?: number;
|
startingLevel?: number;
|
||||||
foodsPerLevel?: number;
|
foodsPerLevel?: number;
|
||||||
maxLevel?: number;
|
maxLevel?: number;
|
||||||
|
initialFoodCount?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function useGameStatus(
|
export function useGameStatus(
|
||||||
@@ -19,6 +20,7 @@ export function useGameStatus(
|
|||||||
const startingLevel = params?.startingLevel ?? 1;
|
const startingLevel = params?.startingLevel ?? 1;
|
||||||
const foodsPerLevel = params?.foodsPerLevel ?? 10;
|
const foodsPerLevel = params?.foodsPerLevel ?? 10;
|
||||||
const maxLevel = params?.maxLevel ?? 25;
|
const maxLevel = params?.maxLevel ?? 25;
|
||||||
|
const initialFoodCount = params?.initialFoodCount ?? 1;
|
||||||
const { containerRef } = boardManager;
|
const { containerRef } = boardManager;
|
||||||
const { initSnake, clearSnake, snakeBodyRef } = snakeManager;
|
const { initSnake, clearSnake, snakeBodyRef } = snakeManager;
|
||||||
const { spawnFood, clearFood } = foodManager;
|
const { spawnFood, clearFood } = foodManager;
|
||||||
@@ -38,7 +40,7 @@ export function useGameStatus(
|
|||||||
|
|
||||||
const startGame = () => {
|
const startGame = () => {
|
||||||
initSnake();
|
initSnake();
|
||||||
spawnFood(snakeBodyRef.current, 3);
|
spawnFood(snakeBodyRef.current, initialFoodCount);
|
||||||
setScore(0);
|
setScore(0);
|
||||||
setLevel(startingLevel);
|
setLevel(startingLevel);
|
||||||
levelRef.current = startingLevel;
|
levelRef.current = startingLevel;
|
||||||
|
|||||||
Reference in New Issue
Block a user