Home > Software engineering >  Can't figure out unity scene load delay
Can't figure out unity scene load delay

Time:12-02

So the problem here is that i'm trying to delay the sceneload and show a win screen for a few seconds, unlock the next level(which works btw) and fade the player into a portal. Instead it just loads the next scene instantly when i enter my portal. Can't seem to figure it out myself.

`public float menuCounter; public int nextSceneLoad;

void Start()
{
   nextSceneLoad = SceneManager.GetActiveScene().buildIndex   1;
}

void Update()
{
    menuCounter -= Time.deltaTime;



    if (menuCounter is >= 0.1f and <= 0.2f)
    {
        SceneManager.LoadScene(nextSceneLoad);
    }
    if (menuCounter is >= 1.8f and <= 1.9f)
    {
        GameObject.Find("Sprite").GetComponent<SpriteRenderer>().material.color = new Color(1f, 1f, 1f, 0.9f);
    }
    if (menuCounter is >= 1.7f and <= 1.8f)
    {
        GameObject.Find("Sprite").GetComponent<SpriteRenderer>().material.color = new Color(1f, 1f, 1f, 0.8f);
    }
    if (menuCounter is >= 1.6f and <= 1.7f)
    {
        GameObject.Find("Sprite").GetComponent<SpriteRenderer>().material.color = new Color(1f, 1f, 1f, 0.7f);
    }
    if (menuCounter is >= 1.5f and <= 1.6f)
    {
        GameObject.Find("Sprite").GetComponent<SpriteRenderer>().material.color = new Color(1f, 1f, 1f, 0.6f);
    }
    if (menuCounter is >= 1.4f and <= 1.5f)
    {
        GameObject.Find("Sprite").GetComponent<SpriteRenderer>().material.color = new Color(1f, 1f, 1f, 0.5f);
    }
    if (menuCounter is >= 1.3f and <= 1.4f)
    {
        GameObject.Find("Sprite").GetComponent<SpriteRenderer>().material.color = new Color(1f, 1f, 1f, 0.4f);
    }
    if (menuCounter is >= 1.2f and <= 1.3f)
    {
        GameObject.Find("Sprite").GetComponent<SpriteRenderer>().material.color = new Color(1f, 1f, 1f, 0.3f);
    }
    if (menuCounter is >= 1.1f and <= 1.2f)
    {
        GameObject.Find("Sprite").GetComponent<SpriteRenderer>().material.color = new Color(1f, 1f, 1f, 0.2f);
    }
    if (menuCounter is >= 1f and <= 1.1f)
    {
        GameObject.Find("Sprite").GetComponent<SpriteRenderer>().material.color = new Color(1f, 1f, 1f, 0.1f);
    }
    if (menuCounter is >= 0.2f and <= 1f)
    {
        GameObject.Find("Sprite").GetComponent<SpriteRenderer>().enabled = false;
    }
}

void OnTriggerEnter2D(Collider2D other)
{
    if (other.CompareTag("Player"))
    {
        if (SceneManager.GetActiveScene().buildIndex == 4)
        {
            Debug.Log("You Completed ALL Levels");

            //Show Win Screen or Somethin.
        }
        else
        {
            //Move to next level
            

            //Setting Int for Index
            if (nextSceneLoad > PlayerPrefs.GetInt("levelAt"))
            {
                PlayerPrefs.SetInt("levelAt", nextSceneLoad);
            }
            menuCounter = 2f;
            GameObject.Find("Player").GetComponent<Movement>().enabled = false;
            GameObject.Find("Player").GetComponent<Rigidbody2D>().bodyType =  RigidbodyType2D.Static;
            GameObject.Find("StageClear").GetComponent<TextMeshProUGUI>().enabled = true;
            GameObject.Find("StageClearSound").GetComponent<AudioSource>().enabled = true;
            GameObject.Find("MusicControl").GetComponent<AudioSource>().enabled = false;
        }
    }
}

} `

I've tried adding a coroutine and Invoke with a delay but couldn't get it to work.

CodePudding user response:

I would definitely use a routine instead of Update for this.

Main reason: The Update runs all the time. So it is pretty much possible that you run through all of the conditions before you collide since menuCounter will with or without collision eventually reach <= 0.2f => directly jumps into

SceneManager.LoadScene(nextSceneLoad);

Another reason: With your setup yo might easily skip a condition and maintenance will be really bad if you want to adjust the times or add/remove steps ;)

I would probably rather do something like this

int currentScene;
int nextSceneLoad;

void Start()
{
   currentScene = SceneManager.GetActiveScene().buildIndex;
   nextSceneLoad = currentScene   1;
}

private bool isAlreadyLoading;

// "OnTriggerEnter2D" can return IEnumerator in which case
// Unity will automatically tread and run it as a coroutine
IEnumerator OnTriggerEnter2D(Collider2D other)
{
    // if already loading ignore
    if(isAlreadyLoading) yield break;

    // if not player ignore
    if (!other.CompareTag("Player")) yield break;
    
    if (currentScene == 4)
    {
        Debug.Log("You Completed ALL Levels");

        //Show Win Screen or something
    }
    else
    {
        if (nextSceneLoad > PlayerPrefs.GetInt("levelAt"))
        {
            PlayerPrefs.SetInt("levelAt", nextSceneLoad);
            // I would also save this
            PlayerPrefs.Save();
        }
           
        // In general "Find" is very expensive!
        // you already seem to have a reference to the player since it collided with you!
        other.GetComponent<Movement>().enabled = false;
        other.GetComponent<Rigidbody2D>().bodyType =  RigidbodyType2D.Static;
        GameObject.Find("StageClear").GetComponent<TextMeshProUGUI>().enabled = true;
        GameObject.Find("StageClearSound").GetComponent<AudioSource>().enabled = true;
        GameObject.Find("MusicControl").GetComponent<AudioSource>().enabled = false;

        // set flag to ignore any later collisions
        isAlreadyLoading = true;

        // store these ONCE
        var sprite = GameObject.Find("Sprite").GetComponent<SpriteRenderer>();
        var material = sprite.material;

        // if I'm not completely mislead I think you want to fade out your sprite
        // from fully white opaque to fully transparent
        var startColor = Color.white;
        var targetColor = new Color(1f, 1f, 1f, 0f);
        // Coudld be a const or even better adjustable via the Inspector
        float fadeDuration = 2f;

        // Every frame move the timePassed forward and interpolate the sprite color
        for(var timePassed = 0f; timePassed < fadeDuration; timePassed  = Time.deltatime)
        {
            // will be a factor moving 0 -> 1 within fadeDuration
            var factor = timePassed / fadeDuration;
            // interpolate startColor -> targetColor within fadeDuration
            sprite.color = Color.Lerp(statColor, targetColor, factor);
            // "pause" routine here, render this frame and continue from here in next frame
            yield return null;
        }

        sprite.enabled = false;

        // wait an additional second
        yield return new WaitForSeconds(1f);

        // finally load the scene
        SceneManager.LoadScene(nextSceneLoad);
    }
}
  • Related