gale.tilemap package

gale.tilemap: grid-of-tiles maps — rendering (with gale.camera culling built in), tileset slicing, and grid/pixel coordinate conversion, independent of where the map data comes from. IsometricTileMap (plus the standalone cartesian_to_isometric/isometric_to_cartesian transforms) renders the same kind of layered, tileset-backed map in a diamond/isometric projection instead of the default orthogonal one.

load_tiled_map loads a map exported by Tiled (https://www.mapeditor.org/) as JSON, including its tilesets and object layers (spawns, triggers…, exposed as plain data for the game to interpret).

Collision is a separate, opt-in layer on top (move_and_collide): solid tiles block in every direction, platform tiles are one-way (stand on top, jump up through). Anything richer (slopes, hazards, ladders…) is deliberately left to the game, read from whatever custom tile properties it defines in Tiled — this module never requires gale.physics/Box2D, or any particular physics approach at all.

See docs/examples/tilemap.rst for a walkthrough.

Author: Alejandro Mujica (aledrums@gmail.com)

class gale.tilemap.CollisionType[source]

Bases: object

The two kinds of blocking tile move_and_collide understands, read from a tile’s custom property (see collision_type_at). Everything else — slopes, conveyor belts, ladders, hazards — is deliberately left out: define your own property (e.g. “damage”) and read it with TileMap.properties_of_gid/get_gid yourself, the same way these two are read.

NONE: str = 'none'
SOLID: str = 'solid'
PLATFORM: str = 'platform'
class gale.tilemap.IsometricTileMap(tile_width, tile_height, cols, rows)[source]

Bases: TileMap

A TileMap rendered as a 2:1 isometric diamond grid rather than an axis-aligned one — same rows x cols grid(s) of gids, same tileset(s)/layers/object_layers API, only the projection from (row, col) to pixels (and back) changes.

Conventions used throughout this class:

  • (row 0, col 0) sits at the map’s top corner (the diamond’s topmost point on screen), with row increasing toward the bottom-left and col increasing toward the bottom-right — the usual isometric “diamond” layout.

  • position_of(row, col) returns that cell’s diamond’s top vertex (not a bounding-box top-left corner), shifted right by origin_x = (rows - 1) * tile_width / 2 so the whole map’s top vertex column never goes negative.

  • Tile images are anchored at their top-center: the pixel position_of returns is where the top-center point of the tile_width x tile_height source image should land. render() accounts for this by blitting at (position_of(row, col)[0] - tile_width / 2, position_of(row, col)[1]).

Because row + col increases monotonically along a plain row-major (row ascending, then col ascending) iteration, that iteration order already paints back-to-front for a diamond grid — no extra sort is needed, unlike a general isometric scene with freely-placed entities.

Usage example:

tileset = Tileset(tiles_image, tile_width=64, tile_height=32, first_gid=1) tilemap = IsometricTileMap(tile_width=64, tile_height=32, cols=20, rows=20) tilemap.add_tileset(tileset) ground = tilemap.add_layer(“ground”) ground[5][10] = 1

# Every frame: tilemap.render(surface, camera)

Parameters:
  • tile_width (int)

  • tile_height (int)

  • cols (int)

  • rows (int)

property pixel_width: int
property pixel_height: int
position_of(row, col)[source]
Parameters:
  • row (int) – A tile row.

  • col (int) – A tile column.

Returns:

The screen/world pixel position of that cell’s diamond’s top vertex (see the class docstring for the anchor/origin convention).

Return type:

Tuple[float, float]

tile_at(x, y)[source]
Parameters:
  • x (float) – A screen/world x position, in pixels.

  • y (float) – A screen/world y position, in pixels.

Returns:

The (row, col) of the tile whose diamond contains that point (not clamped to this map’s bounds — check in_bounds if the point might fall outside it).

Return type:

Tuple[int, int]

render(surface, camera=None)[source]
Parameters:
  • surface (Surface) – The surface to draw every layer onto.

  • camera (Any | None) – A gale.camera.Camera to translate/scale tiles through and cull whatever falls outside its viewport. The default value is None, rendering the whole map at a 1:1 scale starting at (0, 0).

Return type:

None

class gale.tilemap.TileMap(tile_width, tile_height, cols, rows)[source]

Bases: object

A grid of tile layers (each a rows x cols grid of gids, 0 meaning “empty”) sharing one coordinate system, plus the tileset(s) that render them and any object layers (spawn points, triggers…) carried along for the game to interpret however it wants.

Layers render in the order they were added (the first one is the back-most), the same top-to-bottom-is-back-to-front convention gale.ui.Container uses for widgets.

Usage example:

tilemap = TileMap(tile_width=16, tile_height=16, cols=50, rows=12) tilemap.add_tileset(Tileset(tiles_image, 16, 16, first_gid=1)) ground = tilemap.add_layer(“ground”) ground[5][10] = 1 # place tile gid 1 at row 5, col 10

# Every frame: tilemap.render(surface, camera)

Typically built by load_tiled_map rather than by hand — see docs/examples/tilemap.rst.

Parameters:
  • tile_width (int)

  • tile_height (int)

  • cols (int)

  • rows (int)

property pixel_width: int
property pixel_height: int
add_tileset(tileset)[source]
Parameters:

tileset (Tileset) – A Tileset to make available to this map’s layers. Order doesn’t matter — tileset_for_gid resolves the right one for a given gid regardless of add order.

Return type:

None

add_layer(name, grid=None)[source]
Parameters:
  • name (str) – This layer’s name, used to refer back to it (get_layer, get_gid, collision helpers…).

  • grid (List[List[int]] | None) – The layer’s initial rows x cols gids. The default value is None, filling a new all-empty (every gid 0) grid.

Returns:

The layer’s grid (also reachable later through get_layer), so it can be filled in directly.

Return type:

List[List[int]]

layer_names()[source]
Returns:

Every tile layer’s name, in render order (back to front).

Return type:

List[str]

get_layer(name)[source]
Parameters:

name (str) – A layer added through add_layer.

Returns:

That layer’s rows x cols grid of gids.

Return type:

List[List[int]]

get_gid(layer_name, row, col)[source]
Parameters:
  • layer_name (str) – A layer added through add_layer.

  • row (int) – A tile row.

  • col (int) – A tile column.

Returns:

The gid at that cell (0 means empty).

Return type:

int

set_gid(layer_name, row, col, gid)[source]
Parameters:
  • layer_name (str) – A layer added through add_layer.

  • row (int) – A tile row.

  • col (int) – A tile column.

  • gid (int) – The gid to place there (0 to clear it).

Return type:

None

in_bounds(row, col)[source]
Returns:

Whether (row, col) falls inside this map’s rows x cols grid.

Parameters:
  • row (int)

  • col (int)

Return type:

bool

tile_at(x, y)[source]
Parameters:
  • x (float) – A world x position, in pixels.

  • y (float) – A world y position, in pixels.

Returns:

The (row, col) of the tile containing that point (not clamped to this map’s bounds — check in_bounds if the point might fall outside it).

Return type:

Tuple[int, int]

position_of(row, col)[source]
Parameters:
  • row (int) – A tile row.

  • col (int) – A tile column.

Returns:

The world pixel position of that cell’s top-left corner.

Return type:

Tuple[float, float]

tileset_for_gid(gid)[source]
Parameters:

gid (int) – A global tile id.

Returns:

Whichever added Tileset’s range gid falls in, or None (gid is 0/empty, or out of range of every tileset added so far).

Return type:

Tileset | None

properties_of_gid(gid)[source]
Parameters:

gid (int) – A global tile id.

Returns:

That tile’s custom properties (as set on the tile in Tiled’s tileset editor), or {} if it has none or gid is empty/unknown.

Return type:

Dict[str, Any]

render(surface, camera=None)[source]
Parameters:
  • surface (Surface) – The surface to draw every layer onto.

  • camera (Any | None) – A gale.camera.Camera to translate/scale tiles through and cull to only the visible range. The default value is None, rendering the whole map at a 1:1 scale starting at (0, 0).

Return type:

None

exception gale.tilemap.TiledLoadError[source]

Bases: Exception

Raised when a Tiled JSON export uses a feature load_tiled_map doesn’t support.

class gale.tilemap.TiledObject(name, type, x, y, width, height, properties=<factory>)[source]

Bases: object

One entry from a Tiled object layer (a spawn point, a trigger, a checkpoint…) — plain data. What each one means, and what to do with it, is entirely up to the game; load_tiled_map never interprets name/type itself.

Parameters:
  • name (str)

  • type (str)

  • x (float)

  • y (float)

  • width (float)

  • height (float)

  • properties (Dict[str, Any])

name: str
type: str
x: float
y: float
width: float
height: float
properties: Dict[str, Any]
class gale.tilemap.Tileset(image, tile_width, tile_height, first_gid=1, margin=0, spacing=0, tile_properties=None)[source]

Bases: object

One tileset image, sliced into tiles, occupying a contiguous range of global tile ids (gids) starting at first_gid — the same model Tiled (https://www.mapeditor.org/) uses to let a single map reference more than one tileset image.

Usage example:

tileset = Tileset(pygame.image.load(“tiles.png”), 16, 16, first_gid=1)

Parameters:
  • image (Surface)

  • tile_width (int)

  • tile_height (int)

  • first_gid (int)

  • margin (int)

  • spacing (int)

  • tile_properties (Dict[int, Dict[str, Any]] | None)

property tile_count: int
property last_gid: int
contains(gid)[source]
Parameters:

gid (int) – A global tile id.

Returns:

Whether gid falls within this tileset’s range.

Return type:

bool

rect_for(gid)[source]
Parameters:

gid (int) – A global tile id known to be within this tileset’s range (see contains).

Returns:

The area of this tileset’s image that gid’s tile occupies.

Return type:

Rect

properties_for(gid)[source]
Parameters:

gid (int) – A global tile id known to be within this tileset’s range (see contains).

Returns:

gid’s custom properties, or {} if it has none.

Return type:

Dict[str, Any]

gale.tilemap.cartesian_to_isometric(x, y, tile_width, tile_height)[source]

Converts a cartesian grid-space position (in tile units — x is the column, y is the row, either can be fractional) into isometric screen-space pixel coordinates, using the standard 2:1 diamond projection.

Parameters:
  • x (float) – A grid-space x coordinate, in tile units (column).

  • y (float) – A grid-space y coordinate, in tile units (row).

  • tile_width (int) – The width, in pixels, of a diamond tile.

  • tile_height (int) – The height, in pixels, of a diamond tile.

Returns:

The equivalent (screen_x, screen_y) in pixels.

Return type:

Tuple[float, float]

gale.tilemap.collision_type_at(tilemap, layer_name, row, col, collision_property='collision')[source]
Parameters:
  • tilemap (TileMap) – The map to check.

  • layer_name (str) – Which of its layers to check.

  • row (int) – A tile row.

  • col (int) – A tile column.

  • collision_property (str) – The custom tile property (set in Tiled’s tileset editor) collision-checking reads. The default value is “collision”.

Returns:

One of the CollisionType constants: CollisionType.NONE for an empty cell, an out-of-bounds cell, or a tile whose collision_property isn’t “solid”/”platform”.

Return type:

str

gale.tilemap.isometric_to_cartesian(screen_x, screen_y, tile_width, tile_height)[source]

The exact inverse of cartesian_to_isometric: turns an isometric screen-space pixel position back into a cartesian grid-space one (in tile units).

Parameters:
  • screen_x (float) – A screen-space x coordinate, in pixels.

  • screen_y (float) – A screen-space y coordinate, in pixels.

  • tile_width (int) – The width, in pixels, of a diamond tile.

  • tile_height (int) – The height, in pixels, of a diamond tile.

Returns:

The equivalent (x, y) in grid space (tile units).

Return type:

Tuple[float, float]

gale.tilemap.load_tiled_map(path)[source]
Parameters:

path (str) – Path to a map exported by Tiled as JSON.

Returns:

A TileMap with every tile layer, tileset, and object layer the export contains.

Raises:

TiledLoadError – If the map is infinite, or uses a tile layer/tileset encoding this loader doesn’t support (compressed tile data, or a tileset referenced in the old XML .tsx format).

Return type:

TileMap

gale.tilemap.move_and_collide(tilemap, layer_name, x, y, width, height, dx, dy, collision_property='collision')[source]

Moves an entity’s top-left corner by (dx, dy), one axis at a time (x, then y — the usual order for a 2D platformer, so a corner case sliding along a wall still gets stopped by the wall rather than a floor first), snapping it flush against whatever it runs into instead of leaving a gap.

Works entirely in floats, and never rounds x/y to whole pixels anywhere internally — including for the tile-overlap test itself, not just for the position you get back. Rounding either one is enough to reintroduce the bug this is written to avoid: at a typical frame rate, one frame’s movement under gravity near the ground is a fraction of a pixel, so an entity resting on solid ground keeps re-falling that fraction and re-colliding every frame — which reads as the ground-check flickering on and off, since a rounded position can stay numerically unchanged call after call while the real, unrounded one keeps drifting down into the floor. Round only when you need a pygame.Rect for rendering/hit testing elsewhere (e.g. pygame.Rect(round(x), round(y), width, height)).

A “solid” tile blocks in every direction. A “platform” tile only blocks downward movement, and only if the entity was already at or above the platform’s top edge before this call — never from below (walking/jumping up through it) or from the sides (walking through it at the same height).

Parameters:
  • tilemap (TileMap) – The map to collide against.

  • layer_name (str) – Which of its layers to collide against.

  • x (float) – The entity’s current x position (top-left corner), before this move.

  • y (float) – The entity’s current y position (top-left corner), before this move.

  • width (float) – The entity’s width.

  • height (float) – The entity’s height.

  • dx (float) – Horizontal movement this call, in pixels (e.g. vx * dt).

  • dy (float) – Vertical movement this call, in pixels (e.g. vy * dt).

  • collision_property (str) – Forwarded to collision_type_at.

Returns:

(new_x, new_y, collided_x, collided_y) — the resulting position, and whether it was stopped short on each axis.

Return type:

Tuple[float, float, bool, bool]

Submodules