Repository navigation
feat: Add culling support for out of view tiles in TiledComponent - #4124
Merged
Merged
Conversation
Orthogonal tile layers of infinite maps are split into chunks, each with its own SpriteBatch, and only the chunks that touch the view of the camera are rendered. Finite maps can opt in with the new chunkSize parameter of TiledComponent.load and the RenderableTiledMap factories. Chunks are only used when every tile fits in its cell, since tiles that stick out of their cell would be drawn in another order. A chunk is always rendered once a transform of one of its tiles was handed out by tileStack, because the tile can be moved. A map that is rendered without a camera renders everything. With the atlas, a 496 x 496 tile map takes about 0.15 ms to render instead of 15 ms, and without the atlas about 4 ms instead of 230 ms (debug mode, CPU time of recording the frame). Adds a benchmark, tests, and two examples that show the difference.
The Tiled map files that the tests and the benchmark write have attributes like tilewidth and staggeraxis, which the spell checker does not know.
…d maps Isometric, staggered and hexagonal layers now use the chunks of the orthogonal layers too. The chunk size can be set for every orientation, and infinite maps are split in the chunks that they have in Tiled. A layer is only split when its tiles are as big as the cells of the map and have no offset. That used to need square cells, but a cell that is not square, like the 2:1 cells of an isometric map, is fine as long as no tile is turned a quarter, since that swaps the width and the height of a tile. The tiles of the layers of staggered and hexagonal maps that are painted after their row keep their coordinates in TileTransform, so they end up in the right chunk.
The maps that the culling tests render are Tiled files in test/assets now, so that they can be opened in Tiled, instead of being written by the tests. Adds tests for the layers of isometric, staggered and hexagonal maps. Each map is rendered with and without chunks, with and without a camera, and the pixels have to be the same. They also cover maps with cells that are not square, infinite maps with other chunks and chunks at negative coordinates, the real dungeon maps, and the maps that have to stay in one batch.
Renders isometric, staggered and hexagonal maps of 208 and 496 tiles per side, with and without chunks, with and without the atlas.
…mples The Tiled culling examples have an Orientation knob. They show an orthogonal, isometric, staggered or hexagonal map of 400 x 400 tiles. The new maps are terrain made of diamonds and hexagons, as big as the cells of their maps, which is what lets them be split in chunks. The visualized example draws the chunks of an isometric map as diamonds, and the others as the box that Flame compares with the view.
TiledComponent
ufrshubham
marked this pull request as ready for review
October 21, 2026 15:05
- A map in the viewport of a camera, or added to the game directly, is not rendered through the camera that its view comes from, so it is no longer culled. - A layer is only kept whole because of the tilesets that it uses, not because of the other tilesets of the map. - Whether a layer is split is decided again when its cache is refreshed, so a tile that is turned a quarter later keeps the layer whole.
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
Right now every tile of a Tiled layer is part of a single
SpriteBatch, which is drawn on everyframe, even when most of the map is outside of the screen. For big maps this is the main cost of
rendering.
This PR splits a layer into chunks of tiles, each with its own
SpriteBatch, and draws only thechunks that overlap the area the camera sees. It works for all four orientations: orthogonal,
isometric, staggered and hexagonal.
How to use it
maps that get really big.
chunkSizeoption (in tiles perside, for example 16). A map that doesn't use it renders exactly as before.
Things to be aware of
size as the cells of the map, no
tileOffset, and an image tileset. Tiles are drawn in the orderof the rows, so for tiles that are bigger than a cell, drawing them chunk by chunk could change
which one is on top. Layers that don't pass this check are drawn as one batch, like before. This is
the case for the maps with taller tiles.
art does not stay in its cell.
tileStackon a tile keeps its chunk drawn, so a tile that is handed out for changes does notdisappear.
Tests and examples
and without a camera. All the maps they use are
.tmxfiles, so they can be opened in Tiled.CullWhenOffscreen: one shows the speed with culling on and off,and one draws the chunk grid. Both have an orientation knob.
tile_layer_benchmark.dartbenchmarks all orientations.Demo (Windows)
tiled_culling_visualized_windows.mp4
tiled_culling_visualized_isometric_windows.mp4
tiled_culling_visualized_staggered_windows.mp4
tiled_culling_visualized_hexagonal_windows.mp4
Checklist
docsand added dartdoc comments with///.examplesordocs.Breaking Change?
Related Issues