greyBow
greyBow

Reputation: 1348

Coroutine couldn't be started because the the game object is inactive

I'm getting an error of "Coroutine couldn't be started because the the game object 'TimeOutWarningDialog' is inactive!" but I'm unsure why I'm getting this error.

Just to give a rundown of the code:

  1. I'm looking for inactivity in GameManger.Update()

  2. If inactive for a period of time I call GameManager.ShowRestartWarning()

  3. TimeOutWarningDialog gets SetActive to true

  4. I check if the object is active before calling StartRestartTimer(), if (timerInstance.activeSelf == true) StartRestartTimer();

  5. I call startTimer() in CountdownTimer class

I'm setting the object that I'm instatiating to 'active' before I call the startTimer function which includes the coroutine. what am I doing wrong here? any help would be great!!

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

public class GameManager : MonoBehaviour 
{
    // Create Singleton
    public static GameManager instance = null;

    // Set Default Background Color
    public Color defaultColor;

    // Restart variables
    private Vector3 prevMousePosition;
    public GameObject timeOutWarningDialog;
    public GameObject restartDialog;
    public float countdownLength;
    public float timeUntilCountdown;

    // Game Controller
    private GameObject canvas;
    private GameObject gameManager;
    public GameObject timerInstance;
    public Object startingScene;
    private Scene currentScene;

    // File System List of Folders
    public List<string> folders;

    void Awake()
    {
        if (instance == null)
            instance = this;
        else if (instance != null)
            Destroy(gameObject);

        DontDestroyOnLoad(gameObject);

        gameManager = GameObject.FindGameObjectWithTag("GameManager");
    }

    void Start()
    {       
        prevMousePosition = Input.mousePosition;
        currentScene = SceneManager.GetActiveScene();
    }

    void Update()
    {
        if(Input.anyKeyDown || Input.mousePosition != prevMousePosition)
            if(currentScene.name != startingScene.name)
                StartGameTimer();
        prevMousePosition = Input.mousePosition;
    }

    // GAME TIMER

    void StartGameTimer()
    {
        //  Debug.Log("Game Timer Started");
        CancelInvoke();

        if (GameObject.FindGameObjectWithTag("Timer") == null)
            Invoke("ShowRestartWarning", timeUntilCountdown);
    }

    void ShowRestartWarning()
    {
        canvas = GameObject.FindGameObjectWithTag("Canvas");

        timerInstance = Instantiate(timeOutWarningDialog);
        timerInstance.transform.SetParent(canvas.transform, false);
        timerInstance.SetActive(true);

        if (timerInstance.activeSelf == true)
            StartRestartTimer();
    }

    void StartRestartTimer()
    {
        CountdownTimer countdownTimer = timeOutWarningDialog.GetComponent<CountdownTimer>();
        countdownTimer.startTimer(countdownLength);

        CancelInvoke();
        Invoke("RestartGame", countdownLength);
    }

    void RestartGame()
    {
        SceneManager.LoadScene(startingScene.name);

        Debug.Log("Game Restarted");
        Debug.Log("Current Scene is " + currentScene.name + ".");
    }

    void DestroyTimer()
    {
        Destroy(GameObject.FindGameObjectWithTag("Timer"));
    }
}

then I'm calling startTimer in the CountdownTimer class below:

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class CountdownTimer : MonoBehaviour
{
    public float countdownLength;
    public Text timerText;
    public bool stop = true;
    private float minutes;
    private float seconds;

    public void startTimer(float from)
    {
        stop = false;
        countdownLength = from;
        Update();
        StartCoroutine(updateCoroutine());
    }

    void Update()
    {
        if (stop) return;
        countdownLength -= Time.deltaTime;

        minutes = Mathf.Floor(countdownLength / 60);
        seconds = countdownLength % 60;
        if (seconds > 59) seconds = 59;
        if (minutes < 0)
        {
            stop = true;
            minutes = 0;
            seconds = 0;
        }
    }

    private IEnumerator updateCoroutine()
    {
        while (!stop)
        {
            timerText.text = string.Format("{0:0}:{1:00}", minutes, seconds);
            yield return new WaitForSeconds(0.2f);
            Debug.Log(string.Format("{0:0}:{1:00}", minutes, seconds));
        }
    }
}

Upvotes: 2

Views: 7713

Answers (1)

Bizhan
Bizhan

Reputation: 17085

The problem is in this method:

void StartRestartTimer()
{
    CountdownTimer countdownTimer = timeOutWarningDialog.GetComponent<CountdownTimer>();
    countdownTimer.startTimer(countdownLength);

    CancelInvoke();
    Invoke("RestartGame", countdownLength);
}

You start the coroutine first and then invoke RestartGame to load another scene. So the object with the coroutine gets destroyed.


I can't give you the solution because it requires more knowledge regarding your scenes but you may want to try additive scene loading.

Upvotes: 1

Related Questions