1

I'm having trouble figuring out how to reset the inactivity countdown of my timer. I'm using a coroutine to take care of the countdown and then stopping the countdown via button press using StopCoroutine. But when the countdown dialog reinstatiates and starts back up again (after inactivity) the count starts at the value it left off on previously. How do I reset the count to start at the full countdown amount each time my counter instantiates?

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

public class GameManager : MonoBehaviour 
{
    public static GameManager gameManagerInstance = null; // Create Singleton
    public Color defaultBackgroundColor;                 
    public Object startingScene;
    public GameObject timeOutWarningDialog;

    private float countdownLength = 15;
    private float countdownDelay = 5;
    private float countdownInterval = 1;
    private IEnumerator counter;
    private Button stopCountButton;
    private Text timerTextField;
    private Vector3 prevMousePosition;
    private Scene currentScene;
    private GameObject gameManager;
    private GameObject canvas;
    private GameObject timerInstance;

    void Awake()
    {
        if (gameManagerInstance == null)
            gameManagerInstance = this;
        else if (gameManagerInstance != null)
            Destroy(gameObject);
        DontDestroyOnLoad(gameObject);
        gameManager = GameObject.FindGameObjectWithTag("GameManager");
    }

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

    void Update()
    {
        if (Input.anyKeyDown || Input.mousePosition != prevMousePosition)
        {
            currentScene = SceneManager.GetActiveScene();

            if (currentScene.name != startingScene.name)
                StartPreCountTimer();
                if (timeOutWarningDialog != null)
                    timeOutWarningDialog.SetActive(false);
        }
        prevMousePosition = Input.mousePosition;
    }

    // GAME TIMER

    public void StartPreCountTimer()
    {
        CancelInvoke();
        if (GameObject.FindGameObjectWithTag("Timer") == null)
            Invoke("ShowRestartWarning", countdownDelay);
    }

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

        timerInstance = Instantiate(timeOutWarningDialog); // instantiate timeout warning dialog
        timerInstance.transform.SetParent(canvas.transform, false);
        timerInstance.SetActive(true);

        Text[] textFields = timerInstance.GetComponentsInChildren<Text>(true); // get reference to timer textfields
        timerTextField = textFields[1]; // access and assign countdown textfield

        stopCountButton = timerInstance.GetComponentInChildren<Button>(); // get reference to keep playing button
        stopCountButton.onClick.AddListener(StopTimer); // add button listener

        if (timerInstance.activeSelf == true)
            StartCoroutine(counter);
    }

    IEnumerator RunTimer(float seconds)
    {
        float s = seconds;
        while (s > 0)
        {
            if (timerTextField != null)
                timerTextField.text = s.ToString();
            yield return new WaitForSeconds(countdownInterval);
            s -= 1;
        }

        if (s == 0)
        {
            RestartGame();
        }
    }

    void StopTimer()
    {
        StopCoroutine(counter);
        Destroy(timerInstance);
    }

    void RestartGame()
    {
        SceneManager.LoadScene(startingScene.name);
    }
}
greyBow
  • 1,298
  • 3
  • 28
  • 62
  • using while to implement a timer, very inefficient! – David Jun 14 '17 at 13:18
  • @David how you recommend that i do it? – greyBow Jun 14 '17 at 13:22
  • @David Also interested in your answer: always though that using `while` loops inside coroutines was the easiest way to do it (I personally use a timer `float` variable that is in/decremented every frame using `Time.deltaTime`). – Kardux Jun 14 '17 at 13:45

1 Answers1

1

You need to assign a new reference to counter if you want to reset (it's not properly a reset, but just a new coroutine) the code inside the coroutine.

I.E.:

void StopTimer() {
    StopCoroutine(counter);
    counter = RunTimer(countdownLength);
    Destroy(timerInstance);
}
Galandil
  • 4,169
  • 1
  • 13
  • 24
  • Excellent, thank you! so if I'm creating a new reference to counter each time does the old reference get destroyed when I Destroy(timerInstance)? – greyBow Jun 14 '17 at 14:22
  • Sorry, I put the new reference to `counter` in the wrong place, edited to correct the mistake. Always better to give the new reference just after `StopCoroutine`, to show that the intention is to "reset" that coroutine. – Galandil Jun 14 '17 at 14:37
  • @greyBow please do not forget to accept the answer if it solved your problem. If not, comment away what's missing. – Galandil Jun 17 '17 at 11:12