Skip to content

Commit 0f77e30

Browse files
committed
perf: Setting tilemap tiles now leverages TileChangeData introduced in unity 2021.2 to reduce excessive tilemap API calls
1 parent 9ba0ef2 commit 0f77e30

File tree

6 files changed

+125
-138
lines changed

6 files changed

+125
-138
lines changed

Assets/LDtkUnity/Editor/Builders/LDtkBuilderIntGridValue.cs

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -81,35 +81,36 @@ public void BuildIntGridValues()
8181
$"Level:{Layer.LevelReference.Identifier}, Layer:{Layer.Identifier}, IntGridValue:{intGridValue}");
8282
continue;
8383
}
84-
84+
8585
IntGridValueDefinition intGridValueDef = intGridValueDefs[index];
86-
TileBase tile = defToTile[intGridValueDef];
8786

8887
LDtkProfiler.BeginSample("GetTilemapToBuildOn");
8988
TilemapTilesBuilder tilemapToBuildOn = GetTilemapToBuildOn(defToKey[intGridValueDef]);
9089
LDtkProfiler.EndSample();
9190

9291
//Set all the tilemap call configurations, but set the actual tile later via an optimized SetTiles
9392
LDtkProfiler.BeginSample("ConvertCellCoord");
94-
Vector3Int cellToPut = ConvertCellCoord(cell);
93+
Vector3Int cellPosition = ConvertCellCoord(cell);
9594
LDtkProfiler.EndSample();
95+
96+
TileBase tile = defToTile[intGridValueDef];
9697

97-
LDtkProfiler.BeginSample("SetPendingTile");
98-
tilemapToBuildOn.SetPendingTile(cellToPut, tile);
98+
LDtkProfiler.BeginSample("intGridValueDef.UnityColor");
99+
Color color = intGridValueDef.UnityColor;
100+
LDtkProfiler.EndSample();
101+
102+
LDtkProfiler.BeginSample("GetIntGridValueScale");
103+
Matrix4x4 matrix = GetIntGridValueScale(tile);
99104
LDtkProfiler.EndSample();
100105

101-
//color & transform
102-
LDtkProfiler.BeginSample("SetColorAndMatrix");
103-
tilemapToBuildOn.SetColor(cellToPut, intGridValueDef.UnityColor);
104-
Matrix4x4? matrix = GetIntGridValueScale(tile);
105-
if (matrix != null)
106-
{
107-
tilemapToBuildOn.SetTransformMatrix(cellToPut, matrix.Value);
108-
}
109-
106+
LDtkProfiler.BeginSample("construct TileChangeData");
107+
TileChangeData data = new TileChangeData(cellPosition, tile, color, matrix);
108+
LDtkProfiler.EndSample();
109+
110+
LDtkProfiler.BeginSample("AddTileChangeData");
111+
tilemapToBuildOn.AddTileChangeData(ref data);
110112
LDtkProfiler.EndSample();
111113
}
112-
113114
LDtkProfiler.EndSample();
114115

115116
LDtkProfiler.BeginSample("IterateAllTilemaps");
@@ -120,7 +121,7 @@ public void BuildIntGridValues()
120121
Tilemap tilemap = builder.Map;
121122

122123
LDtkProfiler.BeginSample("IntGrid.ApplyPendingTiles");
123-
builder.ApplyPendingTiles(true);
124+
builder.ApplyIntGridTiles();
124125
LDtkProfiler.EndSample();
125126

126127
tilemap.SetOpacity(Layer);
@@ -203,8 +204,9 @@ private Tilemap CreateNewTilemap(TilemapKey key)
203204
/// <summary>
204205
/// There's also scaling code from <see cref="LDtkBuilderLevel.BuildLayerInstance"/> and also in the tileset builder for scale there
205206
/// </summary>
206-
private Matrix4x4? GetIntGridValueScale(TileBase tile)
207+
private Matrix4x4 GetIntGridValueScale(TileBase tile)
207208
{
209+
//todo consider job-ifying this to run this math in parallel
208210
Vector2 scale = Vector2.one;
209211

210212
//make the scale correct across every pixels per unit configuration from the importer
@@ -214,7 +216,7 @@ private Tilemap CreateNewTilemap(TilemapKey key)
214216

215217
if (!GetTileDataForTile(tile, out var data))
216218
{
217-
return null;
219+
return Matrix4x4.identity;
218220
}
219221

220222
if (data.colliderType != Tile.ColliderType.Sprite)

Assets/LDtkUnity/Editor/Builders/LDtkBuilderTileset.cs

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Unity.Jobs;
1+
using System.Collections.Generic;
2+
using Unity.Jobs;
23
using UnityEngine;
34
using UnityEngine.Tilemaps;
45

@@ -7,7 +8,9 @@ namespace LDtkUnity.Editor
78
internal sealed class LDtkBuilderTileset : LDtkBuilderLayer
89
{
910
private TileInstance[] _tiles;
10-
private TilemapTilesBuilder _tilesetProvider;
11+
12+
//in most realistic situations, tiles will not overlap, but we can overestimate anyways to avoid resizing
13+
private Dictionary<Vector3Int, int> _depth;
1114

1215
public Tilemap Map;
1316

@@ -87,7 +90,7 @@ public void BuildTileset(TileInstance[] tiles)
8790
LDtkProfiler.EndSample();
8891

8992
LDtkProfiler.BeginSample("new ConstructNewTilemap");
90-
_tilesetProvider = new TilemapTilesBuilder(Map, tiles.Length);
93+
_depth = new Dictionary<Vector3Int, int>(10);
9194
LDtkProfiler.EndSample();
9295

9396
//if we are also an intgrid layer, then we already reduced our position in the intGridBuilder
@@ -102,15 +105,17 @@ public void BuildTileset(TileInstance[] tiles)
102105
Map.SetOpacity(Layer);
103106
LDtkProfiler.EndSample();
104107

105-
LDtkProfiler.BeginSample("CacheNeededTilesArtifacts");
106-
TileBase[] tileAssets = new TileBase[tilesLength];
108+
LDtkProfiler.BeginSample("CacheNeededTilesArtifactsAndSetupColor");
109+
TileChangeData[] tileAssets = new TileChangeData[tilesLength];
110+
//Determine tile asset and setup color while the job is running
107111
LDtkTilesetTile[] artifactTiles = artifacts._tiles;
108112
int artifactCount = artifactTiles.Length;
109113
for (int i = 0; i < tilesLength; i++)
110114
{
111-
int? t = _tiles[i].T;
115+
tileAssets[i].color = new Color(1, 1, 1, _tiles[i].A);
112116

113-
//it's possible that a t value is null in the json, unfortunately
117+
int? t = _tiles[i].T;
118+
//it's possible that a t value is null in the json, unfortunately for performance's sake
114119
if (t == null)
115120
{
116121
continue;
@@ -122,11 +127,12 @@ public void BuildTileset(TileInstance[] tiles)
122127
int tValue = t.Value;
123128
if (tValue < artifactCount)
124129
{
125-
tileAssets[i] = artifactTiles[tValue];
130+
tileAssets[i].tile = artifactTiles[tValue];
126131
}
127132
}
128133
LDtkProfiler.EndSample();
129134

135+
//Job is done, we can use the output now!
130136
LDtkProfiler.BeginSample("handle.Complete");
131137
handle.Complete();
132138
LDtkProfiler.EndSample();
@@ -135,35 +141,24 @@ public void BuildTileset(TileInstance[] tiles)
135141
job.Input.Dispose();
136142
LDtkProfiler.EndSample();
137143

138-
LDtkProfiler.BeginSample("RecalculateCellPositions");
139-
Vector3Int[] cells = new Vector3Int[tilesLength];
144+
LDtkProfiler.BeginSample("RecalculateCellPositionsAndSetupMatrix");
140145
for (int i = 0; i < tilesLength; i++)
141146
{
142-
cells[i] = job.Output[i].Cell;
143-
cells[i].z = _tilesetProvider.GetNextCellZ(cells[i]);
147+
//todo find a way to improve performance of this somehow where we dont need to make a vector3int copy
148+
Vector3Int cell = job.Output[i].Cell;
149+
cell.z = GetNextCellZ(cell);
150+
tileAssets[i].position = cell;
151+
tileAssets[i].transform = job.Output[i].Matrix;
144152
}
145153
LDtkProfiler.EndSample();
146154

147155
LDtkProfiler.BeginSample("Tilemap.SetTiles");
148-
Map.SetTiles(cells, tileAssets);
149-
LDtkProfiler.EndSample();
150-
151-
LDtkProfiler.BeginSample("SetColorAndMatrix");
152-
for (int i = 0; i < tilesLength; i++)
153-
{
154-
Color color = new Color(1, 1, 1, _tiles[i].A);
155-
Matrix4x4 matrix = job.Output[i].Matrix;
156-
_tilesetProvider.SetColorAndMatrix(cells[i], ref color, ref matrix);
157-
}
156+
TilemapTilesBuilder.SetTiles(Map, tileAssets);
158157
LDtkProfiler.EndSample();
159158

160159
LDtkProfiler.BeginSample("Output.Dispose");
161160
job.Output.Dispose();
162161
LDtkProfiler.EndSample();
163-
164-
LDtkProfiler.BeginSample("ApplyExtraData");
165-
_tilesetProvider.ApplyExtraData();
166-
LDtkProfiler.EndSample();
167162

168163
LDtkProfiler.BeginSample("CompressBounds");
169164
Map.CompressBounds();
@@ -174,5 +169,18 @@ private TilesetDefinition EvaluateTilesetDefinition()
174169
{
175170
return Layer.OverrideTilesetUid != null ? Layer.OverrideTilesetDefinition : Layer.TilesetDefinition;
176171
}
172+
173+
/// <param name="cell">Z is always 0</param>
174+
private int GetNextCellZ(Vector3Int cell)
175+
{
176+
if (!_depth.ContainsKey(cell))
177+
{
178+
_depth.Add(cell, 0);
179+
return 0;
180+
}
181+
182+
_depth[cell] += 1;
183+
return _depth[cell];
184+
}
177185
}
178186
}

Assets/LDtkUnity/Editor/Builders/TileBuildingJob.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
namespace LDtkUnity.Editor
77
{
8+
/// <summary>
9+
/// This job is for calculating the tile matrix and cell position for each tile in a layer.
10+
/// </summary>
811
internal struct TileBuildingJob : IJobFor
912
{
1013
public struct InputData
@@ -24,10 +27,10 @@ public struct OutputData
2427
[ReadOnly] public NativeArray<InputData> Input;
2528
[WriteOnly] public NativeArray<OutputData> Output;
2629

27-
[ReadOnly] public int LayerGridSize;
28-
[ReadOnly] public int LayerCWid;
29-
[ReadOnly] public int LayerCHei;
30-
[ReadOnly] public float ScaleFactor;
30+
[ReadOnly] private int LayerGridSize;
31+
[ReadOnly] private int LayerCWid;
32+
[ReadOnly] private int LayerCHei;
33+
[ReadOnly] private float ScaleFactor;
3134

3235
public TileBuildingJob(TileInstance[] tiles, LayerInstance layer, float layerScale)
3336
{
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#if !UNITY_2021_2_OR_NEWER
2+
using UnityEngine;
3+
using UnityEngine.Tilemaps;
4+
5+
namespace LDtkUnity.Editor
6+
{
7+
/// <summary>
8+
/// This artificial struct is for use before Unity 2021.2 where the better tilemap API is introduced for SetTiles with TileChangeData.
9+
/// </summary>
10+
internal struct TileChangeData
11+
{
12+
public Vector3Int position;
13+
public TileBase tile;
14+
public Color color;
15+
public Matrix4x4 transform;
16+
17+
public TileChangeData(Vector3Int position, TileBase tile, Color color, Matrix4x4 transform)
18+
{
19+
this.position = position;
20+
this.tile = tile;
21+
this.color = color;
22+
this.transform = transform;
23+
}
24+
25+
public static void Apply(Tilemap tilemap, TileChangeData[] datas)
26+
{
27+
Vector3Int[] positions = new Vector3Int[datas.Length];
28+
TileBase[] tiles = new TileBase[datas.Length];
29+
30+
for (int i = 0; i < datas.Length; i++)
31+
{
32+
positions[i] = datas[i].position;
33+
tiles[i] = datas[i].tile;
34+
}
35+
36+
tilemap.SetTiles(positions, tiles);
37+
38+
foreach (TileChangeData data in datas)
39+
{
40+
tilemap.SetTransformMatrix(data.position, data.transform);
41+
tilemap.SetColor(data.position, data.color);
42+
}
43+
}
44+
}
45+
}
46+
#endif

Assets/LDtkUnity/Editor/Builders/TileChangeData.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)