Skip to content

Commit 5cd60b3

Browse files
committed
Major Optimization for Tilemap Collision Indexing
This update optimizes an existing feature (Tilemap Collision Indexing). This optimization will apply to [nearly] everyone using procedural generation tilemaps, infinite tilemaps, multiplayer tilemaps, particularly large tilemaps (especially those dyanmic in nature) or who otherwise intend to index collisions before the tiles are loaded. Benchmarking: Using the standard approach, indexing collisions for a 500x450 tileset took 2530ms. By pre-building the collision index array in its entirety, I was able to reduce that to 259ms. However, this implementation reduces it to 8 ms. Larger tilemaps would be exponentially affected. There are some considerations to make here since there are better implementations, but it would require deprecating some existing code. The advantage would be that the standard approach itself would be optimized, (thus avoiding the sort of 2500+ms costs here), rather than fairly obscured as it is with this implementation.
1 parent 106e32a commit 5cd60b3

5 files changed

Lines changed: 50 additions & 25 deletions

File tree

src/tilemaps/Tilemap.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,16 +1660,18 @@ var Tilemap = new Class({
16601660
* @param {boolean} [recalculateFaces=true] - Whether or not to recalculate the tile faces after the
16611661
* update.
16621662
* @param {Phaser.Tilemaps.LayerData} [layer] - [description]
1663+
* @param {boolean} [updateLayer=true] - If true, updates the current tiles on the layer. Set to
1664+
* false if no tiles have been placed for significant performance boost.
16631665
*
16641666
* @return {?Phaser.Tilemaps.Tilemap} Return this Tilemap object, or null if the layer given was invalid.
16651667
*/
1666-
setCollision: function (indexes, collides, recalculateFaces, layer)
1668+
setCollision: function (indexes, collides, recalculateFaces, layer, updateLayer)
16671669
{
16681670
layer = this.getLayer(layer);
16691671

16701672
if (layer === null) { return this; }
16711673

1672-
TilemapComponents.SetCollision(indexes, collides, recalculateFaces, layer);
1674+
TilemapComponents.SetCollision(indexes, collides, recalculateFaces, layer, updateLayer);
16731675

16741676
return this;
16751677
},

src/tilemaps/components/SetCollision.js

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,33 +23,39 @@ var SetLayerCollisionIndex = require('./SetLayerCollisionIndex');
2323
* @param {boolean} [recalculateFaces=true] - Whether or not to recalculate the tile faces after the
2424
* update.
2525
* @param {Phaser.Tilemaps.LayerData} layer - The Tilemap Layer to act upon.
26+
* @param {boolean} [updateLayer=true] - If true, updates the current tiles on the layer. Set to
27+
* false if no tiles have been placed for significant performance boost.
2628
*/
27-
var SetCollision = function (indexes, collides, recalculateFaces, layer)
29+
var SetCollision = function (indexes, collides, recalculateFaces, layer, updateLayer)
2830
{
2931
if (collides === undefined) { collides = true; }
3032
if (recalculateFaces === undefined) { recalculateFaces = true; }
3133
if (!Array.isArray(indexes)) { indexes = [ indexes ]; }
34+
if (updateLayer === undefined) { updateLayer = true; }
3235

3336
// Update the array of colliding indexes
3437
for (var i = 0; i < indexes.length; i++)
3538
{
3639
SetLayerCollisionIndex(indexes[i], collides, layer);
3740
}
38-
41+
3942
// Update the tiles
40-
for (var ty = 0; ty < layer.height; ty++)
43+
if(updateLayer)
4144
{
42-
for (var tx = 0; tx < layer.width; tx++)
45+
for (var ty = 0; ty < layer.height; ty++)
4346
{
44-
var tile = layer.data[ty][tx];
45-
46-
if (tile && indexes.indexOf(tile.index) !== -1)
47+
for (var tx = 0; tx < layer.width; tx++)
4748
{
48-
SetTileCollision(tile, collides);
49+
var tile = layer.data[ty][tx];
50+
51+
if (tile && indexes.indexOf(tile.index) !== -1)
52+
{
53+
SetTileCollision(tile, collides);
54+
}
4955
}
5056
}
5157
}
52-
58+
5359
if (recalculateFaces) { CalculateFacesWithin(0, 0, layer.width, layer.height, layer); }
5460
};
5561

src/tilemaps/components/SetCollisionBetween.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@ var SetLayerCollisionIndex = require('./SetLayerCollisionIndex');
2525
* @param {boolean} [recalculateFaces=true] - Whether or not to recalculate the tile faces after the
2626
* update.
2727
* @param {Phaser.Tilemaps.LayerData} layer - The Tilemap Layer to act upon.
28+
* @param {boolean} [updateLayer=true] - If true, updates the current tiles on the layer. Set to
29+
* false if no tiles have been placed for significant performance boost.
2830
*/
29-
var SetCollisionBetween = function (start, stop, collides, recalculateFaces, layer)
31+
var SetCollisionBetween = function (start, stop, collides, recalculateFaces, layer, updateLayer)
3032
{
3133
if (collides === undefined) { collides = true; }
3234
if (recalculateFaces === undefined) { recalculateFaces = true; }
35+
if (updateLayer === undefined) { updateLayer = true; }
3336

3437
if (start > stop) { return; }
3538

@@ -40,21 +43,24 @@ var SetCollisionBetween = function (start, stop, collides, recalculateFaces, lay
4043
}
4144

4245
// Update the tiles
43-
for (var ty = 0; ty < layer.height; ty++)
46+
if(updateLayer)
4447
{
45-
for (var tx = 0; tx < layer.width; tx++)
48+
for (var ty = 0; ty < layer.height; ty++)
4649
{
47-
var tile = layer.data[ty][tx];
48-
if (tile)
50+
for (var tx = 0; tx < layer.width; tx++)
4951
{
50-
if (tile.index >= start && tile.index <= stop)
52+
var tile = layer.data[ty][tx];
53+
if (tile)
5154
{
52-
SetTileCollision(tile, collides);
55+
if (tile.index >= start && tile.index <= stop)
56+
{
57+
SetTileCollision(tile, collides);
58+
}
5359
}
5460
}
5561
}
5662
}
57-
63+
5864
if (recalculateFaces) { CalculateFacesWithin(0, 0, layer.width, layer.height, layer); }
5965
};
6066

src/tilemaps/dynamiclayer/DynamicTilemapLayer.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -872,20 +872,29 @@ var DynamicTilemapLayer = new Class({
872872
* single numeric index or an array of indexes: [2, 3, 15, 20]. The `collides` parameter controls if
873873
* collision will be enabled (true) or disabled (false).
874874
*
875-
* @method Phaser.Tilemaps.DynamicTilemapLayer#setCollision
875+
* If no layer specified, the map's current layer is used.
876+
*
877+
* @method Phaser.Tilemaps.Tilemap#setCollision
876878
* @since 3.0.0
877879
*
878880
* @param {(integer|array)} indexes - Either a single tile index, or an array of tile indexes.
879881
* @param {boolean} [collides=true] - If true it will enable collision. If false it will clear
880882
* collision.
881883
* @param {boolean} [recalculateFaces=true] - Whether or not to recalculate the tile faces after the
882884
* update.
885+
* @param {Phaser.Tilemaps.LayerData} [layer] - [description]
886+
* @param {boolean} [updateLayer=true] - If true, updates the current tiles on the layer. Set to
887+
* false if no tiles have been placed for significant performance boost.
883888
*
884-
* @return {Phaser.Tilemaps.DynamicTilemapLayer} This Tilemap Layer object.
889+
* @return {?Phaser.Tilemaps.Tilemap} Return this Tilemap object, or null if the layer given was invalid.
885890
*/
886-
setCollision: function (indexes, collides, recalculateFaces)
891+
setCollision: function (indexes, collides, recalculateFaces, layer, updateLayer)
887892
{
888-
TilemapComponents.SetCollision(indexes, collides, recalculateFaces, this.layer);
893+
layer = this.getLayer(layer);
894+
895+
if (layer === null) { return this; }
896+
897+
TilemapComponents.SetCollision(indexes, collides, recalculateFaces, layer, updateLayer);
889898

890899
return this;
891900
},

src/tilemaps/staticlayer/StaticTilemapLayer.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -784,12 +784,14 @@ var StaticTilemapLayer = new Class({
784784
* collision.
785785
* @param {boolean} [recalculateFaces=true] - Whether or not to recalculate the tile faces after the
786786
* update.
787+
* @param {boolean} [updateLayer=true] - If true, updates the current tiles on the layer. Set to
788+
* false if no tiles have been placed for significant performance boost.
787789
*
788790
* @return {Phaser.Tilemaps.StaticTilemapLayer} This Tilemap Layer object.
789791
*/
790-
setCollision: function (indexes, collides, recalculateFaces)
792+
setCollision: function (indexes, collides, recalculateFaces, updateLayer)
791793
{
792-
TilemapComponents.SetCollision(indexes, collides, recalculateFaces, this.layer);
794+
TilemapComponents.SetCollision(indexes, collides, recalculateFaces, this.layer, updateLayer);
793795

794796
return this;
795797
},

0 commit comments

Comments
 (0)