feat: Support infinite maps in flame_tiled - #4074
Merged
Merged
Conversation
tiled 0.12.0 resolves external tilesets and templates through ParserProvider and replaces TsxProvider, so flame_tiled is updated to the new API. - Load external files through the async TiledMap.fromString loader, which is given the path of each referenced file. Object templates are resolved through it as well now, not only tilesets. - FlameTsxProvider implements ParserProvider instead of the removed TsxProvider, so it can still be passed to TiledMap.parseTmx and TiledMap.parseJson for a preloaded tileset. - Drop the direct xml dependency from flame_tiled, it is not used anymore. - Allow xml 7 in flame_kenney_xml, since tiled 0.12 requires it and the workspace resolves a single version. BREAKING CHANGE: flame_tiled re-exports tiled 0.12.0, which replaces TsxProvider with ParserProvider. FlameTsxProvider no longer implements TsxProvider; it implements ParserProvider instead.
Use the TileLayer access APIs from tiled 0.12.0 (contentBounds, tileAt, setTileAt, forEachTile) so that infinite maps, whose tiles live in chunks at possibly negative coordinates instead of in tileData, can be loaded, rendered and edited. Tile layers: - Size the cached transforms from the layer's contentBounds and store them relative to an origin, so tiles at negative Tiled coordinates are supported. Add transformAt/storeTransform to access them. - Iterate tiles through tilesByWorldRow(), which groups the non-empty tiles by row, sorted by y and then x. Infinite layers store tiles chunk by chunk, and painting them in that order would draw overlapping tiles (isometric, staggered, hexagonal and oversized tiles) in the wrong order at chunk borders. Finite maps render exactly as before. RenderableTiledMap: - getTileData/setTileData use TileLayer.tileAt/setTileAt and return null / do nothing for cells outside of the layer instead of throwing. - tileStack uses transformAt, so it works with negative coordinates. Tests and docs: - Add infinite map fixtures and tests for loading, tile access and editing at negative coordinates. - Add golden tests rendering a whole infinite map, an isometric map across the four chunks around the origin, and an orthogonal room with an oversized door tile overlapping walls of two chunks, which fails if tiles are painted chunk by chunk. - Document infinite map support and its current limitations.
4 of 5 tasks
spydon
pushed a commit
that referenced
this pull request
Sep 30, 2026
Upgrades `flame_tiled` from `tiled` 0.11.0 to 0.12.0. 0.12.0 has the new `TileLayer` tile access APIs (`tileAt`, `setTileAt`, `forEachTile`, `contentBounds`), which infinite map support needs. That support is in #4074, which is stacked on this PR. This PR only does the upgrade, so the breaking part can be reviewed on its own. The breaking change in 0.12.0 comes from flame-engine/tiled.dart#72: external tilesets and templates are now resolved through `ParserProvider` instead of `TsxProvider`, and `TileMapParser` is gone. `flame_tiled` re-exports `package:tiled/tiled.dart`, so this reaches Flame users directly. Changes: - **Loading external files:** `RenderableTiledMap.fromString` passes a loader to the new async `TiledMap.fromString`. tiled calls it with the path of every external file the map references, relative to the map, and the loader reads it from the asset bundle. Before, `flame_tiled` had to create a `TsxProvider` per tileset. External object templates (`.tx`) now load through the same path, not only tilesets. - **`FlameTsxProvider`:** now implements `ParserProvider` instead of the removed `TsxProvider`, so it can still be passed to `TiledMap.parseTmx`/`parseJson` for a preloaded tileset. `parse`, `filename`, `data`, `getSource` and `getCachedSource` are still there. - **Dependencies:** - `flame_tiled` no longer depends on `xml` directly. It was only used to build an `XmlParser`, and `Parser.fromString` from `tiled` does that now. - `flame_kenney_xml` now allows `xml` 7 (`>=6.5.0 <8.0.0`). tiled 0.12 requires `xml: ^7.0.0`, and the workspace resolves a single version, so without this the workspace doesn't resolve. `flame_kenney_xml` doesn't depend on `tiled`, and its tests pass on xml 7.0.1. `TiledComponent.load` and `RenderableTiledMap.fromFile`/`fromString` are used exactly as before. The existing tests for external tilesets and `FlameTsxProvider` pass unchanged.
spydon
approved these changes
Sep 30, 2026
spydon
left a comment
Member
There was a problem hiding this comment.
Nice, lgtm!
It was surprisingly little code to solve that.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Stacked on #4073, which upgrades
flame_tiledtotiled0.12.0.Adds support for infinite maps from the Tiled editor.
Until now, loading an infinite map crashed with a null check error. Infinite maps don't have a
single
tileDatagrid. Tiled stores their tiles in chunks, usually 16×16, placed at any tilecoordinate, including negative ones when you paint left of or above the origin.
flame_tiledassumed a
width × heightgrid starting at(0, 0)everywhere:cacheTiles()started withlayer.tileData!, and cached transforms were indexed astransforms[x][y].This PR builds on the new
TileLayertile access APIs from flame-engine/tiled.dart#94(
contentBounds,tileAt,setTileAt,forEachTile), which work the same way for finite andinfinite layers.
Tile layers (
FlameTileLayerand the four orientation layers):contentBounds:(0, 0, width, height)for finitelayers, and the area covered by all chunks for infinite ones. Transforms are stored relative to
that area's top-left corner (
originX/originY), so negative coordinates work.transformAtand
storeTransformdo the offset, so nothing indexes the cache directly anymore.y, each row sorted byx, throughtilesByWorldRow(). This matters because infinite layers store tiles chunk by chunk. Paintingthem in that order would draw all of one chunk before the first row of the chunk next to it.
Tiles that overlap their neighbours (isometric, staggered, hexagonal and oversized tiles) would
then stack wrongly along chunk borders. Finite maps are visited in the same order as before, so
they render exactly the same.
RenderableTiledMap:getTileData/setTileData(and theByLayerIndexvariants) useTileLayer.tileAt/setTileAt. They take the tile coordinates shown in the Tiled editor, so negative coordinateswork on infinite maps. For cells outside the map (or outside every chunk),
getTileDatareturnsnullandsetTileDatadoes nothing. Before, both threw aRangeErrorfor cells outside afinite map.
tileStackusestransformAt, so it also works at negative coordinates.Current limitations (also documented in
tiled.md):implemented yet.
TiledComponent's size still comes from the map'swidthandheight, so tiles at negativecoordinates render outside the component's bounds.
setTileDatacan't create new chunks.Tests:
tileStackat negative coordinates.renderMapRegionToPnghelper that can capture negativecoordinates:
infinite_map.png: a whole infinite map, with two layers across six chunks.infinite_oversized_tiles_orthogonal.png: a dungeon room across the chunk border atx = 0,with a 32×32 door standing in front of the top wall, so its frame overlaps the walls of both
chunks. I checked that this golden fails if tiles are painted chunk by chunk: the wall of the
right chunk then covers half the door.
infinite_oversized_tiles_isometric.png: an isometric scene across the four chunks around theorigin.
Checklist
docsand added dartdoc comments with///.examplesordocs.Breaking Change?
Related Issues
Closes #2855
Closes #3932