1
\$\begingroup\$

I have a game with two scenes, menu and maingame. I have uploaded the game to googleplay. However when I open the game and click on the play button in the menu scene, the next scene (maingame) takes about 4-5 seconds to load. Is there any way to load the maingame along with the menu so that there is no delay in loading?

EDIT

I have added code to the MainMenu.cs file so that when the game starts the LoadSceneAsync function is called and allowSceneActivation is set to false. Once the "play" button is pressed, the activation is set to true. The first time the game loads, there is still a bit of delay however if the player dies and I go the main menu and press play again, there is no delay.

AsyncOperation async;

void Start()
{        
    async = SceneManager.LoadSceneAsync(1);       
    async.allowSceneActivation = false;
}

public void PlayBtnPressed()
{
   async.allowSceneActivation = true;
   AudioManager.audiomanager.Play("PlayButton");       
}
\$\endgroup\$
  • 1
    \$\begingroup\$ What have you tried so far? \$\endgroup\$ – Vaillancourt Sep 2 at 19:25
  • \$\begingroup\$ Level loading in Unity is usually achieved via AsyncOperation or other non-blocking operations. However, one can find several different solutions when using these. \$\endgroup\$ – liggiorgio Sep 2 at 19:39
  • \$\begingroup\$ @Vaillancourt , so far I haven't added any async ops as I'm not sure how to do so...Once the game loads, it directly goes to scene 1 and if the player hits on play (in scene 1), then scene 2 loads... \$\endgroup\$ – single arrow games Sep 3 at 5:06
  • \$\begingroup\$ @liggiorgio , is there any example or sample code that you can share? \$\endgroup\$ – single arrow games Sep 3 at 5:06
1
\$\begingroup\$

Scene Loading

Basic

Tested this in a new project. The idea is to start scene preloading when Return button is pressed and save AsyncOperation that is doing it, disallow scene activation for it and allow it when you need the scene to be loaded as soon as it's ready.

I would expect it to be loaded into memory, be careful if you are RAM-bounded because both scenes will take up memory space until one is unloaded.

Reproduce:

  1. Create a new project.
  2. Create 2 scenes:
    • "menu"
    • "maingame"
  3. Add both scenes to Build Settings.
  4. Open "menu" scene.
  5. Create GameObject and add PreloadSceneInUnity component to it.
  6. Enter playmode.
  7. Press Return and see "maingame (is loading)" in Hierarchy window.
  8. Press Space - "maingame" scene will open.

Code

Git: Preload scene in unity

using System.Collections;

using UnityEngine;
using UnityEngine.SceneManagement;

public class PreloadSceneInUnity : MonoBehaviour
{
    [SerializeField] private string _sceneName = "maingame";
    public string _SceneName => this._sceneName;

    private AsyncOperation _asyncOperation;

    private IEnumerator LoadSceneAsyncProcess(string sceneName)
    {
        // Begin to load the Scene you have specified.
        this._asyncOperation = SceneManager.LoadSceneAsync(sceneName);

        // Don't let the Scene activate until you allow it to.
        this._asyncOperation.allowSceneActivation = false;

        while (!this._asyncOperation.isDone)
        {
            Debug.Log($"[scene]:{sceneName} [load progress]: {this._asyncOperation.progress}");

            yield return null;
        }
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Return) && this._asyncOperation == null)
        {
            Debug.Log("Started Scene Preloading");

            // Start scene preloading.
            this.StartCoroutine(this.LoadSceneAsyncProcess(sceneName: this._sceneName));
        }

        // Press the space key to activate the Scene.
        if (Input.GetKeyDown(KeyCode.Space) && this._asyncOperation != null)
        {
            Debug.Log("Allowed Scene Activation");

            this._asyncOperation.allowSceneActivation = true;
        }
    }
}

Advanced

If you are not satisfied with how scene loading works in UnityEngine.SceneManagement - I suggest you take a look at Addressables package that Unity provides, it has support for scene loading as well, but be aware that it's a lot more complicated to get into and there is a learning curve that requires to learn quite a few more things before scene loading.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Just curious: What's the purpose of the first yield return null; in LoadSceneAsyncProcess? \$\endgroup\$ – Philipp Sep 3 at 13:35
  • \$\begingroup\$ @Philipp I have tested without it and it doesn't make a difference, I guess it's redundant unless you need to wait a frame before loading scene async, but it's from the official documentation about AsyncOperation.allowSceneActivation. I guess it's from some old times when it mattered, I remember having this issue in one of my projects, but my memory of it now is very vague and something tells me it's related to Editor scripting. I am going to remove it since it doesn't seem relevant anymore, good catch, thanks. \$\endgroup\$ – Candid Moon _Max_ Sep 3 at 14:41
  • \$\begingroup\$ @Philipp It might be related to this - answers.unity.com/questions/755196/… - yield return null; will execute this before LateUpdate, maybe it matters for some projects, or some logic should be finished in Update before user could possibly jump to another scene. I cannot come up with a situation like that, so it's based on my hunch. \$\endgroup\$ – Candid Moon _Max_ Sep 3 at 14:43
  • \$\begingroup\$ @CandidMoon_Max_ , thanks a lot for the code...just one question. Is there any way to do these once the splash screen is being shown? \$\endgroup\$ – single arrow games Sep 4 at 12:49
  • 1
    \$\begingroup\$ @Philipp issuetracker.unity3d.com/issues/… > "In 2018, you could get around this by starting a coroutine and waiting one tick. This workaround no longer works for 2019." This is probably it. Waiting yield return null so scene loading would work in Awake. \$\endgroup\$ – Candid Moon _Max_ Sep 6 at 10:39
0
\$\begingroup\$

You can load the next scene asynchronously using SceneManager.LoadSceneAsync() using coroutines. You can use this strategy on a splash / loading screen if you're wanting to see it load before showing the menu.

using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;

public class Example : MonoBehaviour
{
    void Update()
    {
        // Press the space key to start coroutine
        if (Input.GetKeyDown(KeyCode.Space))
        {
            // Use a coroutine to load the Scene in the background
            StartCoroutine(LoadYourAsyncScene());
        }
    }

    IEnumerator LoadYourAsyncScene()
    {

        AsyncOperation asyncLoad = SceneManager.LoadSceneAsync("Scene2");

        // yield to other processes until the scene is loaded
        while (!asyncLoad.isDone)
        {
            yield return null;
        }

        // Do something here like enabling the play button or closing the splash/loading screen
    }
}

Code example from: https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager.LoadSceneAsync.html

EDIT: As has been indicated in the comments, if you want to control when the scene loads, you can use the allowSceneActivation flag on the above AsyncOperation object. asyncLoad.allowSceneActivation = false; When you want it to load the next scene: asyncLoad.allowSceneActivation = true;

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ One problem with this is that the scene will immediately appear and execute as soon as the async loading is finished. Would you know some convenient way to load it but not start rendering and updating it yet? \$\endgroup\$ – Philipp Sep 3 at 10:32
  • \$\begingroup\$ @Philipp docs.unity3d.com/ScriptReference/… \$\endgroup\$ – Candid Moon _Max_ Sep 3 at 10:58
  • 1
    \$\begingroup\$ @CandidMoon_Max_ Maybe you would like to write an own answer which explains and demonstrates how to use this property to load a scene in the background without switching to it immediately? \$\endgroup\$ – Philipp Sep 3 at 11:02
  • \$\begingroup\$ @Philipp I will write it up, thanks. \$\endgroup\$ – Candid Moon _Max_ Sep 3 at 11:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.