flock-tilemap

Tiled TMX tilemap parser and renderer for the Flock engine

flock-tilemap

Parse Tiled TMX tilemaps and render them with the Flock ECS engine.

The parser (Flock::Tilemap::Map) is pure Crystal — no native/GPU dependency — so maps can be loaded and inspected headless (tests, tooling, servers). Rendering turns each visible tile into a Flock::Sprite, drives tile animations, and bridges Tiled objects to game entities.

Prerequisites

Crystal >= 1.16. The parser is headless; rendering needs Flock's native stack — see the Flock prerequisites (brew install sdl3 sdl3_image sdl3_ttf, wgpu-native via ../wgpu-cr). Resolved by relative path, so no shards install.

Features

  • Orientations: orthogonal, isometric, staggered and hexagonal (staggeraxis / staggerindex / hexsidelength).
  • Tilesets: embedded and external (.tsx), single-image spritesheets and "collection of images"; margin / spacing / tileoffset; per-tile class, properties, animation frames and collision shapes.
  • Layers: tile, object, image and group (nested); per-layer opacity, visibility, pixel offset, parallax factors and tint color, in document draw order.
  • Layer data: CSV, base64 (raw / gzip / zlib), or legacy <tile> elements; infinite maps (chunked data, incl. negative coordinates).
  • Custom properties (typed) on maps, tilesets, tiles, layers and objects.
  • Rendering: GID flip flags; layer stacking; animated tiles; collection & spritesheet tilesets; image layers; tile-objects; tileoffset; bounded spawn for large maps.
  • Gameplay bridges: spawn_objects (Tiled objects → entities), cell_center / world_to_tile coordinate helpers, and a one-call install.

Not supported: zstd-compressed layers (no stdlib codec), wang sets / terrain (editor-only), text-object rendering, and world_to_tile for staggered/hexagonal maps.

Limitations

  • batch_items flips: Flock::BatchItem carries no flip/rotation. Horizontal and vertical flips are emulated exactly by mirroring the item's UV rect (the sprite shader samples uv_min + corner * uv_size, so a negative uv_size mirrors that axis). The diagonal flip is a transpose (a real 90° rotation of the quad) and cannot be expressed in an axis-aligned batch item: diagonally-flipped tiles are skipped with a console warning — use Flock::Tilemap.render (the per-entity path) for full flip support.
  • Asset paths are jailed to the map's directory: every external reference (.tsx source, tileset/layer images) is resolved by Flock::Tilemap.resolve_asset, which rejects absolute paths and any .. segment with a Flock::Tilemap::Map::Error — a map file can never point at arbitrary files on the host.

Usage

require "flock-tilemap"

# One-liner: load + render + own textures + animate.
app.add_plugin(Flock::WindowPlugin.new("Game", 800, 600))
app.add_plugin(Flock::RenderPlugin.new)
Flock::Tilemap.install(app, "assets/level.tmx")

Or drive it yourself:

map = Flock::Tilemap::Map.load("assets/level.tmx")          # pure parse (also headless)
textures = Flock::Tilemap.render(map, world, gpu)           # spawn tile sprites
Flock::Tilemap.animate(world, dt)                           # call each frame for animated tiles

# Tiled objects -> game entities:
Flock::Tilemap.spawn_objects(map, world) do |obj, world_pos|
  next unless obj.obj_class == "enemy"
  e = world.spawn
  world.add(e, Flock::Transform2D.new(world_pos))
  world.add(e, Enemy.new(hp: obj.properties.int("hp", 10)))
end

pos = Flock::Tilemap.cell_center(map, col, row)             # grid -> world
col, row = Flock::Tilemap.world_to_tile(map, mouse_world)   # world -> grid (ortho + iso)
# textures.each(&.release) when done (install does this for you).

origin sets the world position of the map's top-left corner. Tiled's Y axis points down, Flock's up, so center a Camera2D on origin + (pixel_width/2, -pixel_height/2). Pass textures: (keyed by a tileset's first_gid) to override an image with an already-loaded texture, or bounds: to spawn only a sub-region of a huge map.

Run

crystal spec                                    # parser tests (headless)
crystal run examples/show_map.cr                # windowed demo (orthogonal)
crystal run examples/show_iso.cr                # windowed demo (isometric)
crystal run examples/show_install.cr            # one-call install() (BMP tileset on disk)
crystal run examples/render_test.cr             # offscreen readback (orthogonal)
crystal run examples/iso_render_test.cr         # offscreen readback (isometric)
crystal run examples/staggered_render_test.cr   # offscreen readback (staggered)
crystal run examples/object_render_test.cr      # object layers + spawn_objects
crystal run examples/animation_test.cr          # animated tiles
crystal run examples/collection_test.cr         # collection-of-images tileset
crystal run examples/coords_test.cr             # coordinate helpers + bounded spawn
WGPU_FRAMES=5 crystal run examples/show_map.cr   # headless smoke

Like Flock, this shard resolves its dependency by relative path (../flock), so no shards install is required to build the examples or specs.

License

MIT — see LICENSE.

Repository

flock-tilemap

Owner
Statistic
  • 0
  • 0
  • 0
  • 0
  • 1
  • about 6 hours ago
  • August 19, 2026
License

MIT License

Links
Synced at

Wed, 19 Aug 2026 12:18:21 GMT

Languages