html5 canvas instead of DOM

This commit is contained in:
2025-12-19 02:31:49 +00:00
parent 41473f3b24
commit 2757d54dbb
10 changed files with 871 additions and 440 deletions
+47 -21
View File
@@ -1,45 +1,71 @@
import { useRef } from "react";
import { CanvasRenderer, type RenderState } from "./CanvasRenderer";
export type BoardData = {
cols: number;
rows: number;
};
export function useBoard() {
const containerRef = useRef<HTMLDivElement | null>(null);
export type UseBoardParams = {
cellSize?: number;
};
const renderBoard = (cols: number, rows: 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 board = document.createElement("div");
board.id = "snake-board";
board.className = "snake-board";
const canvas = document.createElement("canvas");
canvas.id = "snake-canvas";
canvas.className = "snake-canvas";
container.appendChild(canvas);
canvasRef.current = canvas;
for (let r = 0; r < rows; r++) {
const rowDiv = document.createElement("div");
rowDiv.className = "snake-row";
rowDiv.setAttribute("data-r", String(r));
rendererRef.current = new CanvasRenderer(canvas, cols, rows, cellSize);
lastFrameTimeRef.current = performance.now();
}
for (let c = 0; c < cols; c++) {
const cellDiv = document.createElement("div");
cellDiv.className = "snake-cell";
cellDiv.setAttribute("data-r", String(r));
cellDiv.setAttribute("data-c", String(c));
rowDiv.appendChild(cellDiv);
}
board.appendChild(rowDiv);
function renderBoard(cols: number, rows: number) {
if (!canvasRef.current || !rendererRef.current) {
initCanvas(cols, rows);
} else {
rendererRef.current.updateDimensions(cols, rows);
}
}
container.appendChild(board);
};
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,
};
}