Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rule Tile is slow #327

Open
JMartinSync opened this issue Dec 30, 2021 · 11 comments
Open

Rule Tile is slow #327

JMartinSync opened this issue Dec 30, 2021 · 11 comments

Comments

@JMartinSync
Copy link

JMartinSync commented Dec 30, 2021

Hello guys!
Im using this repo for building a Terraria like game.
My map is made by chunk of tiles. Each chunk is 64x64 tiles and have two tilemaps, one for the background and another one with the composite collider for the foreground (the composite collider is just generated manually, and I have to do it the next frame after set the tile map becouse it doesnt work on the same frame I execute the SetTilesBlock).
I instantiate 9 chunks around the player and as soon as he reachs a border of the current chunk I start loading new chunks and unloading others.
While using default tiles this is working well, but as soon as I use rule tiles the game freezes for a moment when new chunks are created (even if I set just one row of the chunk each frame).

At the moment im not storing the tilemap data, Im just generating it on the fly using a perlin noise.
These are the three steps it takes:

  1. Build an array of TileData. TileData contains two int, and id for the background tile and another one for the foreground. This is made using c# tasks.
  2. Use all the tile data for load the tiles from an scriptable object and prepare the Tile Arrays for SetTilesBlock. This is made with c# tasks too.
  3. Set the tile maps blocks.

For fix the lag/freeze problem it would be great to be able to prepare the tile arrays for SetTilesBlock using tasks or thread or anything than doesnt freeze the game. I know that the tilemap cant be changed in another thread, but if I was able to build the arrays with the final sprite/tile value that the rule tile is going to set (this can be done in another thread) will improve the performance enought.

@ChuanXin-Unity
Copy link
Collaborator

Hi, thanks for the feedback!

Unfortunately, the way RuleTiles are being handled right now will take up time from the main thread, which you are experiencing with the game freezes. We will work on making this process multi-threaded or asynchronous to minimise the stalls you see.

Could you share the Unity Editor version and the 2D Extras package version you are using? Also, would it be possible to share a Unity Profiler data capture of the freeze in the game? Hopefully with this, we can provide a workaround to reduce the stall time for you while we work on this.

@JMartinSync
Copy link
Author

JMartinSync commented Jan 22, 2022

Hello!
Sorry for the late reply...

Unity Version: 2020.3.13f1
2D Tilemap Extras: 1.8.1-preview - September 22, 2021

Setting 3 chunks, Full block set:
SetTileBlocksCapture

Settings 3 chunks, 1 row of each per frame:
SetTileBlocksRowCapture

This is the most complex pattern Im trying, 47 rules:
Pattern

@ChuanXin-Unity
Copy link
Collaborator

Hi, sorry for the late reply! This seems rather slow when setting around 69 RuleTiles. Would it be possible to share your RuleTile? You can do so by filing a bug with your project using the Unity Bug Reporter and posting the case number here. Thanks!

@semgilo
Copy link

semgilo commented Jul 9, 2022

@ChuanXin-Unity I get same problem, Any good suggestions about this.

@sorenbn
Copy link

sorenbn commented Mar 28, 2023

Hi, I'm also having some issues with the RuleTile specifically, taking up a lot of my performance. My case is an in-game level editor, where the player can click-and-drag a box area and "preview" the tiles that they want to place at the same time. But doing anything above a 30x30 box area size, kills the performance.

image

Any news on the multi-threaded/asynchronous workflow you were talking about @ChuanXin-Unity ? 🙂 cheers

@ChuanXin-Unity
Copy link
Collaborator

Any news on the multi-threaded/asynchronous workflow you were talking about @ChuanXin-Unity ? 🙂 cheers

Sorry, there is nothing that can be officially mentioned regarding this.

In the meantime, could you share some details on how you are setting Tiles for your editor, as well as how your RuleTiles are setup? Hopefully we can help improve things with the current release. Thanks!

@sorenbn
Copy link

sorenbn commented Apr 5, 2023

Hi @ChuanXin-Unity and thanks for the follow-up.

I've submitted a bug report (case number: IN-37541) with a small sample project containing the minimum to reproduce.
But upon further inspection in this sample project, when trying out the tilemap.SetTiles(cells[], tiles[]), the performance was actually decent (fps increase from 10-15fps to 45-50fps) compared to my actual project , so I might have something extra in my personal project that is slowing down the performance.

Regular SetTile(cell, tileBase):
Performance_SetTile

SetTiles(cells[], tilebase[]):
Performance_SetTilesArray

Another caveat is that each time I'm redrawing to my "preview" layer, I clear the whole map, to give a proper representation of what's being drawn. I'm assuming that only adding/removing the difference in tiles between last draw command and previous draw command, would give a benefit in performance as well, even though it might be a more cumbersome task to do.

Let me know what you think, cheers! 🙂

EDIT: I've changed my code to only add/remove the changes to the preview tilemap, and not redraw the whole tilemap and this has yielded way better performance! Sits at 80-90fps now, when drawing to the preview layerr.
But further optimization would still be preferable, since I also have a "move" tool , which can move entire selected areas. It's currently still sluggish, because the same optimization can't really be applied here.

@ChuanXin-Unity
Copy link
Collaborator

Thanks for the update!

When you are setting a large number of Tiles, using Tilemap.SetTiles will have better performance, as that allows us to batch the request and reduce the overheads in calling Tilemap APIs.

Using the delta difference instead of clearing the Tilemap and re-adding the Tiles also helps a lot, since the Tilemap would not need to recalculate the original Tiles again.

We will continue improving the performance of setting Tiles in the Tilemap, since this is an important use-case for many users.

Would it be possible to share how your "Move" tool works? We could help in improving the performance for that!

@sorenbn
Copy link

sorenbn commented Apr 10, 2023

@ChuanXin-Unity Thanks for the quick reply! And sure thing, here is my move code:

    public void Draw(List<Vector3Int> positions, List<GMTile> tiles, List<PlacementOptions> placementOptions = default)
    {
        tileChangeData = new TileChangeData[positions.Count];

        for (int i = 0; i < positions.Count; i++)
        {
            var matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0.0f, 0.0f, placementOptions[i].Rotation), Vector3.one);
            tileChangeData[i] = new TileChangeData(positions[i], tiles[i].TileAsset, placementOptions[i].Color, matrix);
        }

        map.SetTiles(tileChangeData, true);
    }

This is the profiler data of around 3700 tiles, with clearing the tilemap (tilemap.ClearAllTiles()) before running the draw command:
unity-move-clear

And this is around 5000 tiles, without clearing the tilemap before running the next draw command:
unity-move-no-clear

Is there any way to improve such high number of tiles to be drawn? Each draw command is only run whenever the mouse changes cell, and not constantly in an Update() function.
It might be possible to make a performance improvement like before, where I'm comparing the changes from previous to current draw command, but it's a bit more tricky since the move command move ALL the tiles, and in this case it can be a lot of different tiles. In my previous case it was a "brush" tool, meaning it was the same tile it was box-selecting and drawing with.

Also as a sidenote, I've noticed refreshing the tilemap (tilemap.RefreshAllTiles()) on larger maps has a huge performance impact. Is there any way to refresh tiles in a certain area of the tilemap?

@ChuanXin-Unity
Copy link
Collaborator

Is there any way to improve such high number of tiles to be drawn?

Since you are using the batch methods for the Tilemap, I don't think you can improve it on your own and we will need to improve the internals to make it more performant. You could do the clearing and setting of Tiles using the same SetTiles call (eg. add the set of moved Tiles for the new area and clear the difference from the old area to the new area), instead of clearing and setting in two calls. This would help if there is some overlap in Tiles between the two areas, such as if the Tile in position A remains the same before and after the move operation.

Also as a sidenote, I've noticed refreshing the tilemap (tilemap.RefreshAllTiles()) on larger maps has a huge performance impact. Is there any way to refresh tiles in a certain area of the tilemap?

There isn't a way now, but we can add APIs to allow you to do so. We will add this to our backlog!

@sorenbn
Copy link

sorenbn commented Apr 13, 2023

Since you are using the batch methods for the Tilemap, I don't think you can improve it on your own and we will need to improve the internals to make it more performant. You could do the clearing and setting of Tiles using the same SetTiles call (eg. add the set of moved Tiles for the new area and clear the difference from the old area to the new area), instead of clearing and setting in two calls. This would help if there is some overlap in Tiles between the two areas, such as if the Tile in position A remains the same before and after the move operation.

Alright thanks, I'll try and give it a go!

There isn't a way now, but we can add APIs to allow you to do so. We will add this to our backlog!

That would be very helpful! Looking forward to that. I also see my bug report has been transferred to the internal team. Thanks again for the help @ChuanXin-Unity !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants