ISpritePhysicsOutlineDataProvider is not updating the TilemapCollider2D in the scene immediately

I have multiple ScriptedImporters setup; One is meant for generating a Sprite+TileBase (this uses the sprite editor window functionality to define physics shapes for sprites), and the other ScriptedImporter is for actually placing the tiles in a tilemap, suited for adding to the scene.

The flow DOES work, but not exactly as I would expect.
My expectation is that I should be able to see tilemap collider changes reflect immediately when I change a sprites physics shape, but it doesn’t appear to update. I’ve tried Tilemap.RefreshAllTiles, Reimporting both scripted importers, reverting prefab overrides in the scene, but still no reflected changes. It does however work if I reload the scene by double-clicking a scene file, or switching into play mode.

Changing the pivot point on the sprite DOES update the tile collider immediately in the scene view. Just not physics shape. So I know for sure that the tile asset and sprite asset are being properly referenced in the tilemap.

Basically, I just want to understand how the usual TextureImporter is capable of updating its own tilemap colliders properly in the scene when the physics shape is changed.
Is there any secret API that I might be able to use that the normal TextureImporter’s magic is doing to forcibly update the tilemap collider if that is the route I should take?

Potentially a bug? I think that because the pivot updates but the physics shape doesn’t, tells me that something must be missing or is not completely working the same as the TextureImporter should.

I understand there could be lots of holes in my explanation, and it can appear pretty open-ended as a question, but If any of my explanation sounds vague, then I can make clarifications :slight_smile:

The Collider’s physics shapes are not automatically updated when the Sprite’s physic shape changes. You would need to manually update/reset the Collider itself to get the changes in the Sprite, as automatically updating the Collider’s physics shapes could overwrite some of the user changes that were made. Automatically updating the renderer does not overwrite any user changes, so that is possible.

Thanks for the info! I searched around and found that Unsupported.SmartReset works to help reset the TilemapCollider2D, but I feel as though there could be a better way to handle this, where I can regenerate the collider without needing to reset all the fields in the component. Is there a more straightforward way that I could refresh the tilemap colliders without having to reset the whole component in the scene?

This is the code that I’m currently trying at the end of an import process, and it does appear to work.

EditorApplication.delayCall += () =>
{
    TilemapCollider2D[] colliders = Object.FindObjectsOfType<TilemapCollider2D>();
    foreach (TilemapCollider2D collider in colliders)
    {
        Unsupported.SmartReset(collider);
    }
};

However, I am greatly concerned about the performance of the editor while using this, and also that all of the fields in all the collider components are reset to default.

I’ve seen before that the Texture2D importer refreshes tilemap colliders properly without a hitch. What might be the special functionality behind it? Ideally, I’d like to replicate exactly how the Texture2D importer is doing it.

In the TilemapCollider2D, I see a field called maximumTileChangeCount, and it notes how it can either rebuild incrementally, or fully. I’d be curious if there is a simple way to fully rebuild the collider.

Also in the docs, I found out about this value for TileAnimationFlags for updating physics with animation. I see that it’s possible to rebuild the physics shape for a tilemap collider, but I don’t appear to have my own direct control over rebuilding the TilemapCollider2D.

This also only appears to only be an issue for collider instances already in the scene. If I drag my imported tilemap asset into the scene, that one has a properly updated shape.

Even if there’s an internal function that’s hidden, I’d still be comfortable using that. Again, thanks for the help!

Disabling/Enabling a collider causes it to be recreated.

In terms of assets changing in the Tilemap, doesn’t this provided what you want?

I’m not sure, without looking at the code, if that informs the TilemapCollider2D of the refresh. I would suspect it does. The collider disable/enable should be quicker though I would suggest.

Hi, I can share the entire project to help a little bit. It’s available here from github, Though I understand if it can be difficult to know which files to search for first.
Sometime later when I have more time, I can help specify which files to dig through. It is however in a very experimental state at the moment so things might act up.
https://github.com/Cammin/LDtkToUnity/tree/6c7dedac810263209df1e14ae268da40e6f0bc4
That latest commit should have some code changes that help direct toward what I was experimenting with. It’s a project built for being a package manager package, but it’s also possible it doesn’t work right for you immediately. I can write up some reproduction steps to my issue sometime later :slight_smile:

But these are things I’ve attempted without success (using 2022.3.0)

  • Calling RefreshAllTiles
  • Enabling/Disabling the tilemap collider component
  • Setting the tile asset dirty (Though it’s part of a scripted importer, maybe doesn’t do anything)

What I’ve found does work:

  • Manually using Reset() on the collider from the inspector, or calling Unsupported.SmartReset on it through a MenuItem function
  • Reopening the scene with the tilemap collider instance
  • Entering/Exiting playmode (due to prompting a scene reload)

I believe there were some more things that I have attempted, but I cannot remember them off the top of my head at the moment, But I indeed scoured the web looking around for anything I could to make this work properly. My goal is to refresh this through an automated code process via a ScriptedImporter.

To come back to this post: There’s been something that’s been making me think:

When a TileBase asset is modified in the inspector window, it immediately reflects it’s change into all tilesmaps inside the scene immedietly.

The difference in how i’m handling my tiles is that I generate tile assets upon each ScriptedImporter reimport. And I think it’s not updating tilemap instances in the scene view as a result.

So my current idea is to try and replicate that functionality where the scene refreshes all tilemaps as if a TileBase was being modified in the inspector.

What’s the function that requests a reload of all tilemaps in the scene in a performant way? My own methods are unperformant, and I’d ideally like to reuse that refresh functionality, even if it’s an internal function to unity.

Maybe even setting the imported tile asset as dirty might trigger the special tilemap instance refresh?

@MelvMay @ChuanXin

Sorry for the pings, but I believe I’ve found the right way to ask the question correctly :slight_smile:

The baseline process:
When a TileBase property changes, it immediately refreshes all tilemaps and colliders in the current open scene.

I checked the profiler to see what is causing this to work. and I found a number of tilemap functions related to refreshing the scene. In particular, Physics2D.TilemapColliderPreparePaths and Physics2D.CompositeColliderAddToComposite.

This got me excited, so I tried calling it from Physics2D class, only to find out it didn’t exist. I also tried using an InternalBridge to see if they were internal methods, but I still can’t find them. So I could only suspect that the functions are hidden away from the C# layer.

I’ve tried using EditorUtility.SetDirty(tile) to trigger this, but it doesn’t trigger a scene refresh, maybe because it’s a sub-asset of the ScriptedImporter.

My only guess is that the TileBaseEditor calls this scene refresh, but that seems strange, and I couldn’t find any related information.

Is there any way I could call these physics functions? Or are there any workarounds to trigger this besides triggering it from a TileBase editor inspector? The reason I want to call the functions is for the reasons in my original post at the top.