Skip to content

Commit d2f72fb

Browse files
committed
Create CullTiles component to allow static and dynamic layers to cull when needed
Fixes performance issue with canvas static tile renderer on large maps
1 parent b5fb0b8 commit d2f72fb

5 files changed

Lines changed: 50 additions & 119 deletions

File tree

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
var CullTiles = function (layer, camera, outputArray)
2+
{
3+
if (outputArray === undefined) { outputArray = []; }
4+
5+
outputArray.length = 0;
6+
7+
var tilemapLayer = layer.tilemapLayer;
8+
var mapData = layer.data;
9+
var mapWidth = layer.width;
10+
var mapHeight = layer.height;
11+
var left = (camera.scrollX * tilemapLayer.scrollFactorX) - tilemapLayer.x;
12+
var top = (camera.scrollY * tilemapLayer.scrollFactorY) - tilemapLayer.y;
13+
14+
for (var row = 0; row < mapHeight; ++row)
15+
{
16+
for (var col = 0; col < mapWidth; ++col)
17+
{
18+
var tile = mapData[row][col];
19+
20+
if (tile === null || (tile.index <= 0 && tilemapLayer.skipIndexZero)) { continue; }
21+
22+
var tileX = tile.worldX - left;
23+
var tileY = tile.worldY - top;
24+
var cullW = camera.width + tile.width;
25+
var cullH = camera.height + tile.height;
26+
27+
if (tile.visible &&
28+
tileX > -tile.width && tileY > -tile.height &&
29+
tileX < cullW && tileY < cullH)
30+
{
31+
outputArray.push(tile);
32+
}
33+
}
34+
}
35+
36+
return outputArray;
37+
};
38+
39+
module.exports = CullTiles;

v3/src/gameobjects/tilemap/components/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module.exports = {
22

33
Copy: require('./Copy'),
4+
CullTiles: require('./CullTiles'),
45
Fill: require('./Fill'),
56
FindByIndex: require('./FindByIndex'),
67
ForEachTile: require('./ForEachTile'),

v3/src/gameobjects/tilemap/dynamiclayer/DynamicTilemapLayer.js

Lines changed: 1 addition & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -49,54 +49,9 @@ var DynamicTilemapLayer = new Class({
4949
this.skipIndexZero = false;
5050
},
5151

52-
getTotalTileCount: function ()
53-
{
54-
return this.tileArray.length;
55-
},
56-
57-
getVisibleTileCount: function (camera)
58-
{
59-
return this.cull(camera).length;
60-
},
61-
6252
cull: function (camera)
6353
{
64-
var mapData = this.layer.data;
65-
var mapWidth = this.layer.width;
66-
var mapHeight = this.layer.height;
67-
var culledTiles = this.culledTiles;
68-
var cameraW = camera.width;
69-
var cameraH = camera.height;
70-
var left = this.worldToTileX(0, camera);
71-
var top = this.worldToTileY(0, camera);
72-
73-
culledTiles.length = 0;
74-
75-
for (var row = 0; row < mapHeight; ++row)
76-
{
77-
for (var col = 0; col < mapWidth; ++col)
78-
{
79-
var tile = mapData[row][col];
80-
81-
if (tile === null || (tile.index <= 0 && this.skipIndexZero)) { continue; }
82-
83-
var tileX = tile.worldX - left;
84-
var tileY = tile.worldY - top;
85-
var tileW = tile.width;
86-
var tileH = tile.height;
87-
var cullW = cameraW + tileW;
88-
var cullH = cameraH + tileH;
89-
90-
if (tile.visible &&
91-
tileX > -tileW && tileY > -tileH &&
92-
tileX < cullW && tileY < cullH)
93-
{
94-
culledTiles.push(tile);
95-
}
96-
}
97-
}
98-
99-
return culledTiles;
54+
TilemapComponents.CullTiles(this.layer, camera, this.culledTiles);
10055
},
10156

10257
copy: function (srcTileX, srcTileY, width, height, destTileX, destTileY)

v3/src/gameobjects/tilemap/staticlayer/StaticTilemapLayer.js

Lines changed: 3 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,7 @@ var StaticTilemapLayer = new Class({
4747

4848
this.dirty = true;
4949
this.vertexCount = 0;
50-
this.cullStart = 0;
51-
this.cullEnd = 0;
52-
this.canvasTiles = [];
50+
this.culledTiles = [];
5351

5452
this.setTexture(tileset.image.key);
5553
this.setPosition(x, y);
@@ -85,7 +83,6 @@ var StaticTilemapLayer = new Class({
8583
var tile;
8684
var row;
8785
var col;
88-
var tileIndex;
8986
var texCoords;
9087

9188
if (this.gl)
@@ -186,6 +183,7 @@ var StaticTilemapLayer = new Class({
186183

187184
this.dirty = false;
188185
}
186+
189187
var renderer = this.tilemapRenderer;
190188

191189
renderer.shader.setConstantFloat2(renderer.scrollLocation, camera.scrollX, camera.scrollY);
@@ -203,70 +201,11 @@ var StaticTilemapLayer = new Class({
203201
]
204202
);
205203
}
206-
else if (this.dirty && !this.gl)
207-
{
208-
this.canvasTiles.length = 0;
209-
210-
for (row = 0; row < mapHeight; ++row)
211-
{
212-
for (col = 0; col < mapWidth; ++col)
213-
{
214-
tile = mapData[row][col];
215-
if (tile === null || (tile.index <= 0 && this.skipIndexZero)) { continue; }
216-
217-
this.canvasTiles.push(tile);
218-
}
219-
}
220-
221-
this.dirty = false;
222-
}
223-
},
224-
225-
getTotalTileCount: function ()
226-
{
227-
return this.mapData.length;
228-
},
229-
230-
getVisibleTileCount: function (camera)
231-
{
232-
this.cull(camera);
233-
234-
return (this.cullEnd - this.cullStart) / 6;
235204
},
236205

237206
cull: function (camera)
238207
{
239-
this.cullStart = 0;
240-
this.cullEnd = 0;
241-
242-
var tileWidth = this.map.tileWidth;
243-
var tileHeight = this.map.tileHeight;
244-
245-
var pixelX = this.x - (camera.scrollX * this.scrollFactorX);
246-
var pixelY = this.y - (camera.scrollY * this.scrollFactorY);
247-
var pixelWidth = this.layer.width * tileWidth;
248-
var pixelHeight = this.layer.height * tileHeight;
249-
250-
if (pixelX < camera.x + camera.width + (tileWidth * 2) &&
251-
pixelX + pixelWidth > camera.x + -(tileWidth * 2) &&
252-
pixelY < camera.y + camera.height + (tileHeight * 2) &&
253-
pixelY + pixelHeight > camera.y + -(tileHeight * 2))
254-
{
255-
var interX = Math.max(pixelX, camera.x + -(tileWidth * 2));
256-
var interY = Math.max(pixelY, camera.y + -(tileHeight * 2));
257-
258-
var interWidth = Math.min(pixelX + pixelWidth, camera.x + camera.width + (tileWidth * 2)) - interX;
259-
var interHeight = Math.min(pixelY + pixelHeight, camera.y + camera.height + (tileHeight * 2)) - interY;
260-
261-
interX = ((interX + (camera.scrollX * this.scrollFactorX)) / tileWidth) | 0;
262-
interY = ((interY + (camera.scrollY * this.scrollFactorY)) / tileHeight) | 0;
263-
264-
interWidth = (interWidth / tileWidth) | 0;
265-
interHeight = (interHeight / tileHeight) | 0;
266-
267-
this.cullStart = (interY * this.layer.width + interX) * 6;
268-
this.cullEnd = ((interY + interHeight) * this.layer.height + interX) * 6;
269-
}
208+
TilemapComponents.CullTiles(this.layer, camera, this.culledTiles);
270209
},
271210

272211
destroy: function ()
@@ -275,7 +214,6 @@ var StaticTilemapLayer = new Class({
275214
this.map = undefined;
276215
this.layer = undefined;
277216
this.tileset = undefined;
278-
this.canvasTiles.length = 0;
279217
GameObject.prototype.destroy.call(this);
280218
},
281219

v3/src/gameobjects/tilemap/staticlayer/StaticTilemapLayerCanvasRenderer.js

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,14 @@ var StaticTilemapLayerCanvasRenderer = function (renderer, gameObject, interpola
77
return;
88
}
99

10-
gameObject.upload(camera);
10+
gameObject.cull(camera);
1111

12-
var tiles = gameObject.canvasTiles;
13-
var tileWidth = gameObject.map.tileWidth;
14-
var tileHeight = gameObject.map.tileHeight;
12+
13+
var renderTiles = gameObject.culledTiles;
1514
var tileset = this.tileset;
1615
var frame = gameObject.frame;
1716
var ctx = renderer.gameContext;
18-
var tileCount = tiles.length;
17+
var tileCount = renderTiles.length;
1918
var image = frame.source.image;
2019
var tx = gameObject.x - camera.scrollX * gameObject.scrollFactorX;
2120
var ty = gameObject.y - camera.scrollY * gameObject.scrollFactorY;
@@ -25,16 +24,15 @@ var StaticTilemapLayerCanvasRenderer = function (renderer, gameObject, interpola
2524
ctx.rotate(gameObject.rotation);
2625
ctx.scale(gameObject.scaleX, gameObject.scaleY);
2726
ctx.scale(gameObject.flipX ? -1 : 1, gameObject.flipY ? -1 : 1);
27+
renderer.setAlpha(gameObject.alpha);
2828

2929
for (var index = 0; index < tileCount; ++index)
3030
{
31-
var tile = tiles[index];
31+
var tile = renderTiles[index];
3232

3333
var tileTexCoords = tileset.getTileTextureCoordinates(tile.index);
3434
if (tileTexCoords === null) { continue; }
3535

36-
renderer.setAlpha(gameObject.alpha * tile.alpha);
37-
3836
ctx.drawImage(
3937
image,
4038
tileTexCoords.x, tileTexCoords.y,

0 commit comments

Comments
 (0)