Collision

Pyxen uses a grid-based collision system. Collision bodies live on a spatial grid and the engine detects overlaps between them each frame. This keeps collision detection simple, fast, and deterministic.

Grid maps and grid bodies

A GridMap defines the spatial world — a grid of tiles with a given cell size. A GridBody is a collision rectangle that lives inside that grid.

The entity with a GridMap must be the parent of entities with GridBody. The engine resolves all collisions within a single GridMap independently, which means you can run several different GridMaps in the same world and they won’t interact with each other.

level = world.spawn(
    map=GridMap(rows=20, columns=20, size=(16, 16), image="tileset")
)

player = world.spawn(
    parent=level,
    body=GridBody(pos=(32, 32), size=(16, 16), tag=1, mask=(2,))
)

Entity position

The entity’s position (x, y) is automatically derived from the GridMap collision resolution. When the engine resolves body movement, it updates the entity’s transform to match the body’s resolved position. You don’t set x/y manually on entities with a GridBody — the collision system owns their position.

Moving bodies

To move an entity with a body, set the body’s move property. The engine will attempt the movement and resolve collisions:

def update():
    player.body.move = (0, 0)
    if input.keyboard.right.down:
        player.body.move = (2, 0)

The engine moves the body, checks for collisions, and adjusts the final position.

Tags and masks

Tags and masks control which bodies can collide with each other.

When a moving body encounters another body or tile whose tag is in its mask, it slides against it rather than passing through. This gives you solid collision with smooth movement along walls and obstacles.

player = world.spawn(
    parent=level,
    body=GridBody(pos=(0, 0), size=(16, 16), tag=1, mask=(2, 3))
)

enemy = world.spawn(
    parent=level,
    body=GridBody(pos=(0, 0), size=(16, 16), tag=2, mask=(1,))
)

The player collides with tags 2 and 3 (enemies and walls). The enemy collides with tag 1 (the player). Bodies with tag 0 or no matching mask pass through each other.

Collision callbacks

When a body hits a tile, the engine calls on_hit_tile:

def on_hit_tile(entity, tile):
    # entity hit a solid tile
    pass

When two bodies overlap, the engine calls on_hit_body:

def on_hit_body(entity, other):
    if entity == player:
        entity.health.value -= 1

These run during the collision step, after update() and before rendering.

Tilemap collision

A GridMap defines a grid of tiles, and tiles can be marked as solid using tile tags:

level.map.set(row=0, column=5, tile=(1, 0), tag=2)

Any body whose mask includes that tag will slide against the tile.

How it works

The collision system is grid-based, not pixel-perfect. Bodies are axis-aligned rectangles that move within the grid. Simulations are isolated per GridMap — each GridMap entity runs its own independent collision resolution. This makes collision:

For the full API, see GridBody and GridMap.