useGridCollision
useGridCollision provides a tile-based collision grid with O(1) lookups. Ideal for grid-based games like Snake, tile RPGs, puzzle games, or any game that uses discrete cell movement.
tsx
import { useGridCollision } from "@carverjs/core/hooks";Quick Start #
tsx
import { useGridCollision } from "@carverjs/core/hooks";
function GameBoard() {
const grid = useGridCollision({
config: { width: 20, height: 20, cellSize: 1 },
});
// Place a wall at (5, 5)
grid.setCell(5, 5, 1);
// Check before moving
const canMove = !grid.isCellOccupied(6, 5);
return null;
}Options #
| Option | Type | Description |
|---|---|---|
config | GridCollisionConfig | Required. Grid configuration |
GridCollisionConfig #
| Field | Type | Default | Description |
|---|---|---|---|
width | number | — | Required. Number of cells along X |
height | number | — | Required. Number of cells along Y |
cellSize | number | 1 | World-space size of each cell |
origin | [number, number] | [0, 0] | World-space origin offset |
Return Value #
| Method | Type | Description |
|---|---|---|
setCell(x, y, value) | (number, number, number) => void | Set a cell value. 0 = empty, positive = occupied. |
getCell(x, y) | (number, number) => number | Get cell value. Returns 0 if empty or out of bounds. |
clearCell(x, y) | (number, number) => void | Clear a cell (set to 0) |
isCellOccupied(x, y) | (number, number) => boolean | Check if a cell is non-zero |
worldToGrid(wx, wy) | (number, number) => [number, number] | Convert world coordinates to grid coordinates |
gridToWorld(gx, gy) | (number, number) => [number, number] | Convert grid coordinates to world coordinates (cell center) |
getNeighbors4(x, y) | (number, number) => [number, number, number, number] | Get 4 cardinal neighbor values [up, right, down, left] |
getNeighbors8(x, y) | (number, number) => number[] | Get 8 neighbor values (cardinal + diagonal) |
clearAll() | () => void | Clear the entire grid |
Snake Game Example #
tsx
import { useRef } from "react";
import { useGridCollision } from "@carverjs/core/hooks";
import { useGameLoop } from "@carverjs/core/hooks";
const WALL = 1;
const SNAKE = 2;
const FOOD = 3;
function SnakeGame() {
const grid = useGridCollision({
config: { width: 20, height: 20, cellSize: 1 },
});
const snakeRef = useRef([{ x: 10, y: 10 }]);
useGameLoop((delta) => {
const head = snakeRef.current[0];
const nextX = head.x + 1;
const nextY = head.y;
const cell = grid.getCell(nextX, nextY);
if (cell === WALL || cell === SNAKE) {
// Game over
return;
}
if (cell === FOOD) {
// Grow — don't remove tail
grid.clearCell(nextX, nextY);
}
// Move head
grid.setCell(nextX, nextY, SNAKE);
snakeRef.current.unshift({ x: nextX, y: nextY });
}, { stage: "fixedUpdate", fixedTimestep: true, fixedDelta: 0.15 });
return null;
}Coordinate Conversion #
Convert between world-space and grid-space:
tsx
const grid = useGridCollision({
config: { width: 10, height: 10, cellSize: 2, origin: [-10, -10] },
});
// World position (0, 0) → grid cell (5, 5)
const [gx, gy] = grid.worldToGrid(0, 0);
// Grid cell (5, 5) → world position (1, 1) (cell center)
const [wx, wy] = grid.gridToWorld(5, 5);Type Definitions #
See Types for UseGridCollisionOptions, UseGridCollisionReturn, GridCollisionConfig, and GridCellCallback.