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 #

OptionTypeDescription
configGridCollisionConfigRequired. Grid configuration

GridCollisionConfig #

FieldTypeDefaultDescription
widthnumberRequired. Number of cells along X
heightnumberRequired. Number of cells along Y
cellSizenumber1World-space size of each cell
origin[number, number][0, 0]World-space origin offset

Return Value #

MethodTypeDescription
setCell(x, y, value)(number, number, number) => voidSet a cell value. 0 = empty, positive = occupied.
getCell(x, y)(number, number) => numberGet cell value. Returns 0 if empty or out of bounds.
clearCell(x, y)(number, number) => voidClear a cell (set to 0)
isCellOccupied(x, y)(number, number) => booleanCheck 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()() => voidClear 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.