In my game I instantiate thousands of prefabs when you enter a new zone.
This causes a freeze, so I’d like to show a mini loading screen or overlay while this happens.
I could just show a static screen, but I want the player to know that something is happening if they’re on a slow PC.
Is there any way I can run an animation on another thread or something? I know you can’t instantiate objects on a separate thread.
I have some code to instantiate batches of prefabs e.g. 100 per frame - should I set timescale to 0 any use this approach while playing the animation? This should work but there will be micro stutters in the animation.
Animations are an example of something that should absolutely positively run on the main thread. The whole point is to change what the user sees, which means they need to update every frame and somehow interact with rendering.
So a loading screen animation works exactly the same as any other animation–the only real question is how you manage the actual loading to minimize its interference with the animation.
Setting timescale to zero won’t inherently help with either loading or animating, but might make sense if you’re trying to prevent your ordinary game logic/physics from running during the load process. As long as you make sure that the animation scales with realtime rather than gametime, setting timescale to zero shouldn’t harm anything.
@Kurt-Dekker I don’t want anything to happen until the new zone has finished loading, e.g. I don’t want the player to move around and see things spawning or have things moving due to physics and getting into weird states.
I spawn some complex objects that are bound together - if they move during instantiation they might end up looking a bit funky.
An example is that I load a vehicle made of multiple prefabs by instantiating each prefab.
If I loaded up 10 of 20 prefabs in 1 frame, the vehicle moved bit, then I loaded the next 10, the parts would be dislocated.
Basically I just want to have a loading screen that lets the player know the game hasn’t completely frozen/crashed by playing a simple animation on the UI.
I’ll give it a go and let you know how it turns out!
Gotcha… makes sense, sorta pause the game until all is ready. I guess that might work but setting timescale to zeor does NOT prevent Update() from being called.
To reliably pause the game you probably don’t want a generic “load all these bazillions of items including the player” but rather load it in intelligent phases: load the ground, make the enemy geometry, if they need to have scripts, disable those scripts and make a list of them, then load the player, etc.
Finally when all is good, just do a single trip through that list of all the scripts you turned off and flip them on. Just beware of what runs when:
Also, as @Antistone pointed out above, just make sure your loading animation is set to run with realtime otherwise that will freeze when timescale is zero.
@Kurt-Dekker Yeah it could get messy if I try to generalize the instantiation, some things may be expecting other objects to be there when they aren’t. The good thing is a lot of these scripts use a base class that handles Start and Update and then calls off to abstract OnStart and OnUpdate methods so I could delay calling these methods until the loading screen has closed.
I’ll make sure to set the animation to play at realtime.
Thanks for your input guys. I’ll report back on my findings!
On a per-script basis are you aware you can make Start a Coroutine just by declaring it as an IEnumerator? That won’t solve your entire broad-project issues, but it can be handy. But remember even after the first yield in Start(), Update() starts getting pumped in that script.
Instantiating in a coroutine, using unscaled time on the animator and setting the timescale to 0 seems to have done the trick!
I did hit 1 dependency issue because some code iterates over the instantiated objects on start (but they’re not there yet). So I simply call this code once the coroutine is finished instead.
A gotcha is that if you instantiate 1 object for each yield in the coroutine, it takes A LOT longer to finishing spawning everything (about 10x as long in my tests). I found a batch of 50 instantiations per frame had a good balance between instantiation speed and smoothness of the animation.
I assume this is something to do with all the work unity needs to do for each frame - and I recently discovered that UI animations can have a fairly large overhead.
Just thought I would update you guys in case you were wondering how it went.
It’s maybe not possible to switch anymore for you but in ECS Megacity demo they stream in hundreds of thousands of entities asynchronously in a staging world and then move the whole thing into the play world. This happens during a frame (the move is 1-2 ms) so the player does not even notice this and there is no loading screen required. Just to give an example of how efficient ECS is compared to GameObject workflow. If you are early in the project and have this fix requirement maybe consider looking at it.
Years ago I found a similar bottleneck: if I had 10,000 things to instantiate, I could do them 100 per frame and have it done in 100 frames (under 2 seconds).
If I just added 10,000 things it would lock up for a minute or more.
My speculation at the time was that Unity puts new GameObjects into a pending list that gets integrated with the scene at end of frame, and that pending list is not as efficient as the scene graph to work with.
@exiguous Thanks for that. I might not be able to convert everything to ECS but that video has given me some ideas for improving performance.
I already serialize all of the objects for saving, so I could use a pooling system to reuse objects out of view and move them to the new area.
I’ll definitely consider ECS and the job system for anything else I add in.
Albeit today I would recommend against using Unity ECS, unfortunately. The reason is UT has gone completely silent on it’s ECS and to some people it’s future is unsure. Rumor is they are working on huge changes but it’s just “unfair” to ignore the thirst for information of the community. So there has not been any new version or news regarding DOTS-ECS and there is a chance that the whole thing is cancelled/scrapped/abandoned. At least if you start now there is a huge risk that the API changes significantly and you will have to start over with a new ECS version. Just you know that my initial “hype” and “enthusiasm” has been cooled down significantly. And this is very frustrating.