How to speed up and smooth over any load times on iPhone (preloading, animated loading screens etc)

I am already aware of a big discrepancy with the load times of my app on my 1st generation iPhone versus my current 3GS. I'd like to do all i can to make my load times seem as snappy as possible.

I already know of the following suggestions

  • replace the splash screen (pro only)
  • load a small scene first to be quick and then start real loading

I've heard other suggestions that seem to hint at the potential of preloading gameplay assets by instantiating gameplay prefabs during the menu scene to have them available when you are actually in gameplay scenes. However its not clear to me how these instantiations trigger loading and dont get garbage collected moving between scenes. Wont adding instantiations of prefabs into the menu cause the menu scene to load slower, or is it by pure script instantiation that the actual scene wont load the prefab, rather it will on demand load it when the script instantiates it?

Are there any other better alternatives to this kind of preloading question, can AssetBundles be used locally as a decent way of loading things in an ordered fashion ahead of time.

Are preloading activities efficient if a user moves through your frontend so quickly that they're starting loading the game scene before any useful preloading has had chance to complete. Ie. will a half loaded asset have to be restarted loading again if the current scene is terminated and we head into the game scene proper?

When actually loading, is there a way to entertain the user whilst the loading is occurring, loading bar, music, animations etc. or are actual scene loads completely blocking and require a frozen (black?) screen?

Cheers

That is quite a few questions. Consider posting multiple questions in the future if they get this long. Regardless, I think I can point you in the right direction.

First, it appears that System.Thread is supported. While your users are in the menu screen, you could have a thread routine run in the background and load all the GameObjects you will be using in the game. (Example below.)

To preserve all your game objects that you have loaded, you will need to call `Object.DontDestroyOnLoad(/*your object reference*/)` for each object. Alternatively, you could just add `DontDestroyOnLoad(this)` to the `Awake()` function of a MonoBehaviour script that is already attached to the loaded object. Note though that you will need to call `Object.Destroy()` if you decide to load a new scene and do not need those objects around anymore, otherwise they will persist until the application dies.

However, what about in the case if the user just blows through the menu screen and tries to jump into your game? I think there are two ways to deal with this.

The first way is to just block the user from starting the game by displaying a loading screen (e.g. using a GUITexture) with some sort of animation. Once the thread is finished, you can call `Application.LoadLevel("Your Level");` to jump to the next scene. Of course, you still might have some down time while LoadLevel is invoked, so you could just make your loading screen object stick around with DontDestroyOnLoad() and then manually destroy it when the level is ready to go.

The second way is to note how far the thread has gotten, and then kill it. Put the note into some object that gets preserved into the next scene. When the new scene has loaded, continue loading where the previous thread left off. This is more complicated, however it might get your users playing faster if you prioritize the objects such that objects used sooner are loaded before objects that the player will not encounter for several seconds or more. You will need to use some sort of blocking mechanism if the user gets to a point where an object is needed, but it hasn't been loaded yet.

Threading example code:

// ... in some MonoBehaviour object
public void Start()
{
    m_thread = new Thread(threadExecute);
    m_thread.Start();
}

private System.Thread m_thread;
private float m_value = 0.0f;

private void threadExecute()
{
    // ... normally you would perform object instantiation here.  
    //     Instead, lets do something intensive.  This takes ~10 seconds 
    //     per pass on 2nd gen iPod Touch with OS 3.1.2, Unity iPhone 1.5.1.
    //
    int loopCount = 0;
    while( true )
    {
        Debug.Log("threadExecute process start for iteration " + 
            loopCount.ToString());

        for( int i = 0; i < 10000000; i++ )
            m_value = Mathf.Sqrt((float)(i * i * i));

        Debug.Log("threadExecute process end for iteration " + 
            loopCount.ToString());
        loopCount++;

        // ... ensure the thread will die if we stop playing in editor.  
        //     Otherwise, this thread will keep going until we start a 
        //     new debug session. :/
        if(! Application.isPlaying )  
            break;
    }
    Debug.Log("threadExecute is exiting");
}