flock-tilemap
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_tilecoordinate helpers, and a one-callinstall.
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_itemsflips:Flock::BatchItemcarries no flip/rotation. Horizontal and vertical flips are emulated exactly by mirroring the item's UV rect (the sprite shader samplesuv_min + corner * uv_size, so a negativeuv_sizemirrors 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 — useFlock::Tilemap.render(the per-entity path) for full flip support.- Asset paths are jailed to the map's directory: every external reference (
.tsxsource, tileset/layer images) is resolved byFlock::Tilemap.resolve_asset, which rejects absolute paths and any..segment with aFlock::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.
flock-tilemap
- 0
- 0
- 0
- 0
- 1
- about 6 hours ago
- August 19, 2026
MIT License
Wed, 19 Aug 2026 12:18:21 GMT