Work out only the cells around a painted one on a tilemap (#348)
A painted cell worked out the tiles and blocking cells of the whole map again, so painting got slower the bigger the map. One cell cost 16.8 ms on 60x60 and 54.6 ms on 120x120. Now it costs what is around it: 3.5 ms and 4.0 ms, against 3.4 ms without painting. - The brush, the paint command and its undo name the keys they changed. Each new version of the cells keeps them for the last 16 versions (cellsChangedSince). - The cell index, the tiles of a layer and the blocking cells patch only the changed cells and their eight neighbours. Everything else stays the same object as before. - Both lists are in cell order now, so a patch is one walk that keeps every other entry. - The rectangles are merged row by row. A patch joins again only the rows around it, one row further than the changed cells, and stacks the rest as they were. - A writer that names no keys costs one walk over the cells. A replaced cell object (load, resize, edits at run time) is worked out in full as before. - The tiles a map names come sorted by id. Two trigger tiles on one cell now keep that order, whichever way they were painted. - resolveTilemap walked all tiles every frame, even without painting. It now does so only when the list changed. Found on the way: deleting an outlined autotile can turn the one below into a full box, which cuts a scaled box two rows further down. Merging only the patched rows missed that. It is a test of its own now. A brush stroke on the map doubled to 120x120 runs at 42 fps instead of 28, p95 of a frame 52 ms instead of 92 ms. What still grows with the map is the mesh of a layer, which is built again on every paint. Tests: - tests/core/tilemap-patch.test.ts (new, 7): 400 random steps on two layers with every kind of tile, each compared with a fresh full run - Unit, tilemap and viewport: 1284 green in 57 files - e2e 39 + 40 (atx): ALL PASSED, 107 checks - Gate (atx): 312 files, 4831 tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8a49392d7f
commit
88e1cf1c7d
7 files changed
+773
-112
No files matched your search
@@ -200,7 +200,7 @@ export class TilemapPainter {
|
||||
const stroke = this.stroke;
|
||||
const layer = stroke && this.strokeLayer(stroke);
|
||||
if (!stroke || !layer) return;
|
||||
let changed = false;
|
||||
const changed: string[] = [];
|
||||
for (const at of cells) {
|
||||
if (!inGrid(item.props, at.x, at.y)) continue;
|
||||
const key = cellKey(at.x, at.y);
|
||||
@@ -209,10 +209,10 @@ export class TilemapPainter {
|
||||
stroke.edits.push({ x: at.x, y: at.y, tileId: stroke.tileId });
|
||||
if (stroke.tileId) layer.cells[key] = stroke.tileId;
|
||||
else delete layer.cells[key];
|
||||
changed = true;
|
||||
changed.push(key);
|
||||
}
|
||||
if (!changed) return;
|
||||
cellsChanged(layer.cells);
|
||||
if (changed.length === 0) return;
|
||||
cellsChanged(layer.cells, changed);
|
||||
this.perFrame.request();
|
||||
}
|
||||
|
||||
@@ -229,7 +229,7 @@ export class TilemapPainter {
|
||||
if (value) layer.cells[key] = value;
|
||||
else delete layer.cells[key];
|
||||
}
|
||||
cellsChanged(layer.cells);
|
||||
cellsChanged(layer.cells, stroke.previous.keys());
|
||||
}
|
||||
const item = this.host.items().find((i) => i.id === stroke.objectId);
|
||||
const edits =
|
||||
|
||||
Reference in new issue
Block a user