How do I slow down the Instantiation of lots of saved objects?

Hi,

Ok so I’ve got a problem with instantiating a lot of saved objects at once. I’m working with an open world that generates, saves and loads in chunks. The problem is when the player moves towards a saved chunk and its time to recall all of those saved objects from a file and instantiate them, it causes long freezes.

Does anyone please know a way of slowing this down so that it still reads all of the saved objects, but instantiates them slowly or bit by bit?

public override void F_InstantiateDynamicObjects()
{
    if (m_SceneState == null || m_SceneState.m_dynamicObjects.Count == 0)
        return;

    // Send message
    // Let player know we are loading areas...
    SendMessageToGUIMessenger();

    //create dynamic objects from file, then
    //set state for each of them
    foreach (State s in m_SceneState.m_dynamicObjects)
    {
        // Below Must Match the name of the Folder in Resources Folder in Games Project Assets - Myk
        GameObject go = Instantiate(Resources.Load<GameObject>("ItemDetails/" + s.m_itemDescriptionString).GetComponent<ItemDescription>().m_prefab);
        Savable savable = go.GetComponent<Savable>();
        savable.HandleState(s);
        if (savable.m_isTimeSensitive)
            savable.ShiftTime(m_SceneState.m_notProcessedTime);

    }

    //Debug.Log(this + " has spawned in " + m_dynamicObjects.Count + " saved Objects.");
}

Thanks!

Strongfinger

Never mind, I figured it out myself…

public override void F_InstantiateDynamicObjects()
{
    if (m_SceneState == null || m_SceneState.m_dynamicObjects.Count == 0)
        return;

    // Send message
    // Let player know we are loading areas...
    SendMessageToGUIMessenger();
    // If the game hasn't started yet, let's spawn everything locally at once.
    if (BaseGameController.gameStarted == false)
    {
        //create dynamic objects from file, then
        //set state for each of them
        foreach (State s in m_SceneState.m_dynamicObjects)
        {
            // Below Must Match the name of the Folder in Resources Folder in Games Project Assets - Myk
            GameObject go = Instantiate(Resources.Load<GameObject>("ItemDetails/" + s.m_itemDescriptionString).GetComponent<ItemDescription>().m_prefab);
            Savable savable = go.GetComponent<Savable>();
            savable.HandleState(s);
            if (savable.m_isTimeSensitive)
                savable.ShiftTime(m_SceneState.m_notProcessedTime);
        }
    }
    // Otherwise let's slow it down as the player might be moving around the world.
    else
    {
        // Start Loading and Instantiating the saved Dynamic Objects.
        StartCoroutine(SpawnDynamicObjects());   
    }
  
}

IEnumerator SpawnDynamicObjects()
{
    //create dynamic objects from file, then
    //set state for each of them
    foreach (State s in m_SceneState.m_dynamicObjects)
    {
        // Below Must Match the name of the Folder in Resources Folder in Games Project Assets - Myk
        GameObject go = Instantiate(Resources.Load<GameObject>("ItemDetails/" + s.m_itemDescriptionString).GetComponent<ItemDescription>().m_prefab);
        Savable savable = go.GetComponent<Savable>();
        savable.HandleState(s);
        if (savable.m_isTimeSensitive)
            savable.ShiftTime(m_SceneState.m_notProcessedTime);

        //Debug.Log(this + " has spawned in a " + go.name);

        // We need to slow down the instantiation, because it is too CPU intensive. 
        yield return new WaitForFixedUpdate(); 
    }

    //Debug.Log(this + " has finished spawning in " + m_dynamicObjects.Count + " saved Objects.");
}

So I guess there’s no solution to this then.

Check the profiler, see what part is taking the longest. Could be the activation of created objects, could be your loading method.

You could make the chunk loading asynchronous. Basically you initiate the process, but let the computer finish it without blocking.
The file parsing could be done on a separate thread, eg. in a Task. You can’t do that with Unity objects, so you’d only prepare the data on separate thread, as much as you can, and then create gameObjects and write data to them on the main thread, but sliced. For example, every frame you create only a fraction and yield. You could deativate them right after, and only activate the entire chunk at once when it’s ready.
Of course, your game would have to be written in a way that asynchronous loading and its delay would be handled well (so that you, for example, can’t fall out of the world because the chunk isn’t loaded yet.
The devs of the game INSIDE have a nice video of how they managed to load scenes continuously, without ever showing a loading screen or even having the game stutter (basically, they enable objects of the next scene gradually over multiple frames, just like that).

The profiler does not show instantiation when it happens. But I do know that instantiation is the problem, because it is only happening when a lot of prefabs are being instantiated and it is well known that using instantiation in Unity is a huge job for the CPU.

Before anything is saved in the chunk, like when the player first visits an area objects are first randomly instantiated, but I slow it down by doing a chain reaction of invokes. It would be great if it were possible to do this when loading saved prefabs from a foreach loop as well.

All game objects in my game have data on them that needs to be saved and loaded. Like you say I can’t save and load Game Object data on separate threads. And how would that stop Unity from instantiating an entire list of saved objects at once? The data is saved to a file and loaded from it. It’s very fast at doing that, but the problem here is the CPU intensive “instantiation” of too many objects at once.

What would be great is if there is a way to slow down the foreach loop or use some other way of checking the State s in m_SceneState.m_dynamicObjects one at a time and delaying the next check. Like how I instantiate the objects the first time around using a chain reaction of invokes. But I just don’t know of any way of doing this as an alternative to a foreach loop reading a saved file.

I already activate and deactivate chunks as the player moves around. That was the whole point behind me setting up my game this way. It’s greatly optimised the world, apart from the freezes when instantiating the objects that have been saved in the chunks, it is seamless.

I can’t find the video you mentioned but I don’t work with scenes anyway. I use one main scene for the whole game world. It’s a dynamic procedurally generated destructible world, its not static. Almost everything in the world can be mined/destroyed and new things built. I just have the game world generate the terrain and objects on it as the player moves around and then as the player gets too far away from a chunk, the chunk will save its objects and delete itself. When the player returns to that location a new chunk will be created, it will regenerate a terrain mesh same as before and then it will look up any saved objects that were there last time and instantiate them with whatever data they had on them, like any damage they have taken.

Also scripts cannot find disabled objects in order to enable them. The scripts need to already be aware of them, like added to an array, which is difficult to do in a dynamically generated world like mine. As the world grows and changes, the arrays need to be repopulated. Disabled objects get left out and you end up with a mess of disabled objects getting left behind and the script thinks that chunk is empty so it instantiates new objects and so on. This is why they need to be saved to a file and destroyed and then loaded and instantiated when the player returns to that location.

So I just need a way of slowing down a foreach loop. Or somehow slow down its instantiation of all of the objects it’s just read from the file.

Cheers.