+2 votes

I have been working on a game that will involve a large world displayed in a TileMap. The world consists of separate rooms, but I don't want a loading screen when moving between them. When I try to dynamically add a room to the TileMap (when the player gets close) I get a bit of a stutter, presumably because I'm having to call setcell() so many times (about 6,500). These rooms are being loaded from a file so I think the setcell() is the only bottleneck (no procedural generation happening).

I've tried threading but learned that TileMap is not thread safe. I've read a couple other answers and workarounds but things like removing the TileMap from the tree and adding it again didn't fix the problem for me.

So I tried to simply load the whole world at once. I don't know how big it will be, but I tried 100 rooms, so 65,000 tiles. It seemed to run alright, except for some visual glitches. The only way I know how to describe them is a wavy, "bad signal" kind of effect. Not sure how to troubleshoot that.

Does anyone have any advice on solving this problem? Open to new design solutions as well, but the preference is getting room loading and unloading with threads working.

Thanks

asked Jun 23 in Engine by Ben Humphries (131 points)

1 Answer

0 votes

One bottleneck may be the loading of the room-file, depending on how big that is. loading these in advance asynchronously and adding the room in runtime may work, another optimization is to run the room loading in "physicsprocess" and setting the thread model to multi threaded.

If you still have a hard time getting things to work you may consider the nature of "thread safety". That the tree is not thread safe means (at least in my understanding of the concept and in my many testcases) that a variable isn't guaranteed to have the same value everywhere if set from different threads one shortly after the other, but writing data from an asynchronous source (aka thread) into your tile set shouldn't be a problem as long as you don't depend on being to access that data for the next couple of frames, but the data will rather trickle in over a few milliseconds or so, which in your case I think would be absolutely fine.

alternatively, you can call the "[TileMapNode].duplicate()" method on the tilemap, which generates an exact copy of the tilemap, which should be disconnected from the scene tree (I think, if it isn't you just have to call "getparent().removechild(self)"), make your changes to that asynchronously, and when that is done remove the old one from the tree and add the updated one in it's place.

Yet another solution would be to asynchronously load the file, adding all the tiles you want to add to an array that you only load a few hundred of every frame, and thus spreading the CPU load of adding all the tiles over several ticks.

answered Jun 23 by albinaask (124 points)

Thank you. I've determined the bottleneck is not the loading of the file from disk, but the looped set_cell() calls through testing. I agree that there shouldn't be a problem with setting cells on a different thread, but when I do that the game freezes and crashes with no error or feedback. I've tried removing the tilemap from the scene tree and I still get the same crash behavior.

I would like to avoid manual "thread-like" behavior, like populating the tilemap in smaller chunks because:

  1. A room is a convenient chunk size
  2. Those parameters would have to change on different hardware.

Hi again, don't know if you solved it, but I realised a MUCH neater solution, just create scenes where you have a tilemap representing your rooms, then you just load in those tilemaps in as rooms via the load("whatever you saved them as") and instance them, that way you don't have to fiddle one giant tilemap, and it's much more flexible since you can add NPCS, lamps or you name it as child nodes to the room tilemap and then just load them in as needed all in one go!!!

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.