Files
vim-snake/src/useBoard/useBoard.ts
T
2025-12-19 02:31:49 +00:00

73 lines
1.9 KiB
TypeScript

import { useRef } from "react";
import { CanvasRenderer, type RenderState } from "./CanvasRenderer";
export type BoardData = {
cols: number;
rows: number;
};
export type UseBoardParams = {
cellSize?: number;
};
export function useBoard(params?: UseBoardParams) {
const cellSize = params?.cellSize ?? 24;
const containerRef = useRef<HTMLDivElement | null>(null);
const canvasRef = useRef<HTMLCanvasElement | null>(null);
const rendererRef = useRef<CanvasRenderer | null>(null);
const lastFrameTimeRef = useRef<number>(0);
function initCanvas(cols: number, rows: number) {
const container = containerRef.current;
if (!container) return;
container.innerHTML = "";
const canvas = document.createElement("canvas");
canvas.id = "snake-canvas";
canvas.className = "snake-canvas";
container.appendChild(canvas);
canvasRef.current = canvas;
rendererRef.current = new CanvasRenderer(canvas, cols, rows, cellSize);
lastFrameTimeRef.current = performance.now();
}
function renderBoard(cols: number, rows: number) {
if (!canvasRef.current || !rendererRef.current) {
initCanvas(cols, rows);
} else {
rendererRef.current.updateDimensions(cols, rows);
}
}
function renderFrame(state: RenderState) {
if (!rendererRef.current) return;
const now = performance.now();
const deltaTime = (now - lastFrameTimeRef.current) / 1000;
lastFrameTimeRef.current = now;
rendererRef.current.render(state, deltaTime);
}
function spawnFoodParticles(pos: { r: number; c: number }) {
rendererRef.current?.spawnFoodParticles(pos);
}
function getRenderer(): CanvasRenderer | null {
return rendererRef.current;
}
return {
containerRef,
canvasRef,
renderBoard,
renderFrame,
spawnFoodParticles,
getRenderer,
};
}
export type UseBoardType = ReturnType<typeof useBoard>;