jer
jer

Reputation: 15

Invoke() does not get called

My code:

public class Enemy : MonoBehaviour 
{
    public GameObject deathEffect;
    public float health = 4f;
    public static int EnemiesAlive = 0;
    public int loadToScene;

    void Start ()
    {
        EnemiesAlive++;
    }

    void OnCollisionEnter2D (Collision2D colInfo)
    {
        if (colInfo.relativeVelocity.magnitude > health)
        {
            Die();
        }
    }

    void Die ()
    {
        Instantiate(deathEffect, transform.position, Quaternion.identity);
        EnemiesAlive--;

        if (EnemiesAlive <= 0)
        {
            Debug.Log ("LEVEL WON!");
            Invoke("ChangeScene",2f);
        }
        Destroy(gameObject);
    }

    void ChangeScene()
    {
        Debug.Log ("Hello");
        loadToScene = 1;
        SceneManager.LoadScene (loadToScene);
    }
}

Can anyone point me out why Invoke() does not work? I wanted to add 2 seconds delay before changing scene once the condition (EnemiesAlive <= 0) is fulfilled. Debug.Log ("LEVEL WON!"); is outputted while Debug.Log ("Hello"); is not. I know I can use StartCoroutine also but I wanted to use Invoke() instead.

Upvotes: 1

Views: 221

Answers (2)

Programmer
Programmer

Reputation: 125275

That's because you are calling the Destroy(gameObject) like m.rogalski mentioned and it does not have a chance of executing Invoke("ChangeScene",2f);.

However, I have a feeling that you want to destroy that Object right away without waiting because you want stuff(such as OnCollisionEnter2D) in that script to stop running but at the-same time want to load your scene later on.

If this is the case then you have to put the loading function in a separate script attached to a separate GameObject. This script will not destroy when you call Destroy(gameObject).

1.Create a new GameObject called "SceneLdObj".

2.Attach the script below to the "SceneLdObj" GameObject.

public class SceneLoader : MonoBehaviour
{
    int loadToScene = 1;
    public void ChangeScene(int sceneLevel)
    {
        loadToScene = sceneLevel;
        Invoke("loadScene", 2f);
    }

    private void loadScene()
    {
        SceneManager.LoadScene(loadToScene);
    }
}

Add the script below to the script in your question:

 SceneLoader sceneLoader;

 void Start()
 {
     sceneLoader = GameObject.Find("SceneLdObj").GetComponent<SceneLoader>();
 }

Now, you can the load function from your Die function and it will still work even though the GameObject is already destroyed.

void Die()
{
    Instantiate(deathEffect, transform.position, Quaternion.identity);
    EnemiesAlive--;

    if (EnemiesAlive <= 0)
    {
        Debug.Log("LEVEL WON!");
        //Call that function from another script
        sceneLoader.ChangeScene(1);
    }
    Destroy(gameObject);
}

EDIT:

This should be your new Enemy script:

public class Enemy : MonoBehaviour 
{
    public GameObject deathEffect;
    public float health = 4f;
    public static int EnemiesAlive = 0;
    public int loadToScene;
    SceneLoader sceneLoader;

    void Start ()
    {
        sceneLoader = GameObject.Find("SceneLdObj").GetComponent<SceneLoader>();
        EnemiesAlive++;
    }

    void OnCollisionEnter2D (Collision2D colInfo)
    {
        if (colInfo.relativeVelocity.magnitude > health)
        {
            Die();
        }
    }

    void Die ()
    {
        Instantiate(deathEffect, transform.position, Quaternion.identity);
        EnemiesAlive--;

        if (EnemiesAlive <= 0)
        {
            Debug.Log ("LEVEL WON!");
            //Call that function from another script
            sceneLoader.ChangeScene(1);
        }
        Destroy(gameObject);
    }

    void ChangeScene()
    {
        Debug.Log ("Hello");
        loadToScene = 1;
        SceneManager.LoadScene (loadToScene);
    }
}

Upvotes: 1

mrogal.ski
mrogal.ski

Reputation: 5920

The problem is that Invoke is in fact getting called but your object is destroyed before invoked method executes.
To fix that, move Destroy(gameObject) to the ChangeScene method :

void Die ()
{
    Instantiate(deathEffect, transform.position, Quaternion.identity);
    EnemiesAlive--;

    if (EnemiesAlive <= 0)
    {
        Debug.Log ("LEVEL WON!");
        Invoke("ChangeScene",2f);
    }
}

void ChangeScene()
{
    Debug.Log ("Hello");
    loadToScene = 1;
    Destroy(gameObject);
    SceneManager.LoadScene (loadToScene);
}

You can optionally specify the time after which the object will be destroyed using an overload of Destroy method : Destroy(gameObject, 1.0f) ( will destroy object after one second ).

Upvotes: 2

Related Questions