tilemap-parserv5.2.0GITHUB

Pathfinding: tile-grid A*

Three classes, one flow: NavGrid turns the collision layer into a walkability grid, Pathfinder runs A* over it, and PathFollower steers a sprite along the result with the runner resolving actual movement. The canonical demo is examples/rpg-pathfinding/main.py.

the chainDIAGRAM
NavGrid
tile_map + tileset
walkability grid
Pathfinder
A* over the grid
find_path(start, end)
PathFollower
waypoint steering
update_rpg(...)
CollisionRunner
move_rpg resolves
every step

THE GRID

A NavGrid is built from the same data the physics world uses: the flat tile map and its TilesetCollision. Tiles with solid polygons are walls; one-way tiles are still walkable surfaces.

nav.pyPYTHON
from tilemap_parser import load_map, load_tileset_collision
from tilemap_parser.runtime.navigation import NavGrid, Pathfinder

game_data = load_map("data/map.json")
tile_map = game_data.build_tile_map()           # {(col, row): tile_id}
tileset  = load_tileset_collision("data/collision/terrain.collision.json")

base = NavGrid(tile_map, tileset, (32, 32), map_size=(24, 14))
nav  = base.erode(1.0)                          # inflate walls 1 tile

pathfinder = Pathfinder(nav)
path = pathfinder.find_path((1, 1), (20, 5))    # [(tx, ty), ...] | None
  • find_path(start_tile, end_tile, max_steps=2000) returns None when the destination is unwalkable or unreachable. Path tiles are grid coordinates; multiply by the effective tile size to get world pixels (the follower does this for you).
  • erode(margin) returns a derived grid with walls inflated by margin tiles, so entities keep a corridor from hugging walls. The example uses erode(1.0).
  • NavGrid.for_entity(...) derives the margin from a sprite size automatically: margin = (max(w, h) / 2) / tile_w.

FOLLOWING THE PATH

PathFollower walks the waypoints; each update_rpg() call moves the sprite toward the current waypoint's center at speed, resolving the move through the runner's move_rpg, and advances the waypoint on arrival (default arrival distance: 20% of a tile diagonal).

loop.pyPYTHON
from tilemap_parser import CollisionRunner
from tilemap_parser.runtime.navigation import PathFollower

follower = PathFollower((32, 32))            # effective tile size

runner = CollisionRunner.from_game_type("rpg", (32, 32))

# In your game loop:
waypoint_idx, arrived, hit_x, hit_y = follower.update_rpg(
    enemy, path, waypoint_idx,
    runner, tileset, tile_map,
    speed=200.0, dt=dt,
)
if arrived:
    path = None   # or pick a new destination
  • The returned tuple is (new_waypoint_index, arrived, hit_wall_x, hit_wall_y); branch on arrived to pick the next destination.
  • update_rpg resolves collision against tile_map/tileset_collision via move_rpg, so the follower never walks through walls; it just gets stopped and you read hit_wall_x/y.

WHEN NOT TO USE IT

This is tile-grid pathfinding: good for rooms, mazes and dungeon layouts. It does not reason about height differences, slopes, or dynamic bodies; anything that moves should be handled by your game's steering on top of the path. And for simple "chase the player" AI, steering the sprite at the target each frame is cheaper than a path.