Skip to content

Commit

Permalink
fixed slow load times for refreshing tilemap colliders in the scene view
Browse files Browse the repository at this point in the history
  • Loading branch information
Cammin committed Oct 9, 2023
1 parent b4fe40e commit 5790243
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 53 deletions.
2 changes: 2 additions & 0 deletions Assets/LDtkUnity/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
- To allow the LDtk importer to load Aseprite files, install the [Unity Aseprite Importer](https://docs.unity3d.com/Packages/[email protected]/manual/index.html)
The Aseprite importer requires Unity 2021.3.15 or above

- Fixed the slow load time to reset tilemap colliders in the scene after reimporting a tileset definition file
- Added a notification in the scene view indicating how many tilemap colliders were reset, and how long it took
- Fixed a bug where reordering IntGrid value definitions would use the wrong tile references, and in some cases, cause an exception
- Changed the icons for the imported Project/Level/Tileset to match with the icons from LDtk 1.5

Expand Down
24 changes: 17 additions & 7 deletions Assets/LDtkUnity/Editor/Builders/LDtkBuilderLayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,27 @@ protected void AddTilemapCollider(GameObject tilemapGameObject)

CompositeCollider2D composite = tilemapGameObject.AddComponent<CompositeCollider2D>();
composite.geometryType = Project.GeometryType;
}

TilemapCollider2D collider = tilemapGameObject.AddComponent<TilemapCollider2D>();
ConfigureTilemapCollider(collider);
}

public static bool ConfigureTilemapCollider(TilemapCollider2D collider)
{
if (!collider.GetComponent<CompositeCollider2D>())
{
return false;
}

TilemapCollider2D collider = tilemapGameObject.AddComponent<TilemapCollider2D>();
bool usedByComposite = collider.GetComponent<CompositeCollider2D>();

#if UNITY_2023_1_OR_NEWER
collider.compositeOperation = Collider2D.CompositeOperation.Merge;
collider.compositeOperation = usedByComposite ? Collider2D.CompositeOperation.Merge : Collider2D.CompositeOperation.None;
#else
collider.usedByComposite = true;
collider.usedByComposite = usedByComposite;
#endif
return;
}

tilemapGameObject.AddComponent<TilemapCollider2D>();
return true;
}
}
}
43 changes: 3 additions & 40 deletions Assets/LDtkUnity/Editor/ScriptedImporter/LDtkTilesetImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using UnityEngine.Profiling;
using UnityEngine.Tilemaps;
using Debug = UnityEngine.Debug;
using Object = UnityEngine.Object;

#if LDTK_UNITY_ASEPRITE
using UnityEditor.U2D.Aseprite;
Expand All @@ -32,8 +31,6 @@ namespace LDtkUnity.Editor
[ScriptedImporter(LDtkImporterConsts.TILESET_VERSION, LDtkImporterConsts.TILESET_EXT, LDtkImporterConsts.TILESET_ORDER)]
internal sealed partial class LDtkTilesetImporter : LDtkJsonImporter<LDtkTilesetFile>
{
private static bool _willRefreshTilemapsInScene;

public const string PIXELS_PER_UNIT = nameof(_pixelsPerUnit);

[SerializeField] internal int _pixelsPerUnit = -1;
Expand Down Expand Up @@ -193,8 +190,8 @@ protected override void Import()
ImportContext.AddObjectToAsset("tilesetFile", _tilesetFile, LDtkIconUtility.LoadTilesetIcon());

ImportContext.SetMainObject(outputTexture);
TilemapColliderTileUpdate();

LDtkTilemapColliderReset.TilemapColliderTileUpdate();
}

private LDtkArtifactAssetsTileset MakeAndCacheArtifacts(TextureGenerationOutput output)
Expand Down Expand Up @@ -334,41 +331,7 @@ string MakeAssetName()
Debug.Assert(_additionalTiles.Count == additionalRects.Count);
}

private static void TilemapColliderTileUpdate()
{
//Refresh tilemap colliders in the current scene.
//Tiles would normally not update in the scene view until entering play mode, or reloading the scene, or resetting the component.
//This will immediately update it.
//Using 2023.1+ is much more optimized for this sort of thing.
//This is unfortunately a slow procedure, but there is currently no easy solution found for refreshing tilemap colliders in the scene.

if (_willRefreshTilemapsInScene)
{
return;
}
_willRefreshTilemapsInScene = true;

EditorApplication.delayCall += () =>
{
Profiler.BeginSample("TilemapColliderTileUpdate");
_willRefreshTilemapsInScene = false;

#if UNITY_2023_1_OR_NEWER
TilemapCollider2D[] colliders = Object.FindObjectsByType<TilemapCollider2D>(FindObjectsInactive.Include, FindObjectsSortMode.None);
#elif UNITY_2020_1_OR_NEWER
TilemapCollider2D[] colliders = Object.FindObjectsOfType<TilemapCollider2D>(true);
#else
TilemapCollider2D[] colliders = Object.FindObjectsOfType<TilemapCollider2D>();
#endif
foreach (var collider in colliders)
{
Unsupported.SmartReset(collider);
PrefabUtility.RevertObjectOverride(collider, InteractionMode.AutomatedAction);
}

Profiler.EndSample();
};
}


private bool PrepareGenerate(TextureImporterPlatformSettings platformSettings, out TextureGenerationOutput output)
{
Expand Down
69 changes: 69 additions & 0 deletions Assets/LDtkUnity/Editor/Utility/LDtkTilemapColliderReset.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System.Diagnostics;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.Tilemaps;

namespace LDtkUnity.Editor
{
internal static class LDtkTilemapColliderReset
{
private static bool _willRefreshTilemapsInScene;

public static void TilemapColliderTileUpdate()
{
//Refresh tilemap colliders in the current scene.
//Tiles would normally not update in the scene view until entering play mode, or reloading the scene, or resetting the component.
//This will immediately update it.
//There is currently no easy solution found for refreshing tilemap colliders in the scene, so this is the best solution I could find for now.
//Related forum: https://forum.unity.com/threads/ispritephysicsoutlinedataprovider-is-not-updating-the-tilemapcollider2d-in-the-scene-immediately.1458874/#post-9358610

if (_willRefreshTilemapsInScene)
{
return;
}
_willRefreshTilemapsInScene = true;

EditorApplication.delayCall += () =>
{
_willRefreshTilemapsInScene = false;

Stopwatch watch = Stopwatch.StartNew();

//should only try resetting tilemaps that are in an LDtk hierarchy
var levels = LDtkFindInScenes.FindInAllScenes<LDtkComponentLevel>();
if (levels.IsNullOrEmpty())
{
watch.Stop();
return;
}

var layers = levels.SelectMany(p => p.GetComponentsInChildren<LDtkComponentLayer>()).ToList();
if (layers.IsNullOrEmpty())
{
watch.Stop();
return;
}

var colliders = layers.SelectMany(p => p.GetComponentsInChildren<TilemapCollider2D>()).ToList();
int affected = 0;
foreach (var collider in colliders)
{
Unsupported.SmartReset(collider);
if (LDtkBuilderLayer.ConfigureTilemapCollider(collider))
{
affected++;
}
}
watch.Stop();

SceneView view = SceneView.lastActiveSceneView;
if (view != null && affected > 0)
{
float seconds = watch.ElapsedMilliseconds * 0.001f;
view.ShowNotification(new GUIContent($"Refreshed LDtk scene tilemaps\n({affected} in {seconds:F2}s)"), 2.5f);
}
};
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 1 addition & 6 deletions Assets/Tools/RefreshTilemaps.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,7 @@ private static void UpdateTilemaps()
[MenuItem("LDtkUnity/Refresh Tilemap Colliders", false, 10)]
private static void UpdateTilemapColliders()
{
TilemapCollider2D[] colliders = Object.FindObjectsByType<TilemapCollider2D>(FindObjectsSortMode.None);
foreach (TilemapCollider2D collider in colliders)
{
Unsupported.SmartReset(collider);
PrefabUtility.RevertObjectOverride(collider, InteractionMode.AutomatedAction);
}
LDtkTilemapColliderReset.TilemapColliderTileUpdate();
}

}
Expand Down

0 comments on commit 5790243

Please sign in to comment.