StopCoroutine调用

时间:2017-07-20 21:06:31

标签: c# unity3d timer coroutine

我不确定为什么会这样,但是我有一个倒计时器会触发,当用户点击一个调用StopTimerButton()的按钮时它应该停止。但即使我调用StopCoroutine,计时器也会一直向下计数,直到达到零,然后调用RestartGame()。我的代码中缺少什么?

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

public class CountdownTimer : MonoBehaviour
{
    public static CountdownTimer countdownTimerInstance = null; // create singleton
    public Object startingScene;
    public GameObject timeOutWarningDialog;
    public float preCountdownLength;
    public float countdownLength;

    private GameObject timerDialogBoxInstance;
    private GameObject timerDialogCountdownText;
    private Text timerDialogCountdownTextTarget;
    private GameObject canvas;
    private IEnumerator warningCounter;
    private IEnumerator preCounter;
    private Button stopCountButton;
    private float countdownInterval = 1.0f;
    private bool preCountActive;
    private bool warningCountActive;

    void Awake()
    {
        ResetCountStates();

        if (countdownTimerInstance == null)
            countdownTimerInstance = this;
        else if (countdownTimerInstance != null)
            Destroy(gameObject);
        DontDestroyOnLoad(gameObject);
    }

    void Update()
    {
        bool userActive = GameManager.userActive;
        bool onIntroScreen = GameManager.onIntroScreen;

        if (!userActive && !onIntroScreen && !preCountActive)
            StartPreCountTimer(preCountdownLength); 
        else if (userActive && !onIntroScreen && preCountActive)
            StopPreCountTimer();
    }

    void StartPreCountTimer(float length)
    {
        preCountActive = true;
        preCounter = RunTimer(length);
        StartCoroutine(preCounter);
        Debug.Log("PreCount Started");
    }

    void StopPreCountTimer()
    {
        preCountActive = false;
        StopCoroutine(preCounter);
        Debug.Log("PreCount Stopped");
    }

    void WarningDialog(float length)
    {
        preCountActive = false;
        warningCountActive = true;
        canvas = GameObject.FindGameObjectWithTag("Canvas");
        timerDialogBoxInstance = Instantiate(timeOutWarningDialog); // instantiate timeout warning dialog
        timerDialogBoxInstance.transform.SetParent(canvas.transform, false);
        timerDialogBoxInstance.SetActive(true);
        timerDialogCountdownText = GameObject.FindGameObjectWithTag("CountdownText"); // get reference to countdown text GO
        timerDialogCountdownTextTarget = timerDialogCountdownText.GetComponent<Text>(); // get countdown textfield component
        stopCountButton = timerDialogBoxInstance.GetComponentInChildren<Button>(); // get reference to keep playing button
        stopCountButton.onClick.AddListener(StopTimerButton); // add button listener

        if (warningCountActive && !preCountActive && timerDialogBoxInstance != null)
        {
            warningCounter = RunTimer(length); // create new reference to counter, resets countdown to countdownLength
            StartCoroutine(warningCounter);
        }
    }

    IEnumerator RunTimer(float seconds)
    {
        // PRECOUNT TIMER
        if (!warningCountActive)
        {
            float s = seconds;
            while (s > 0)
            {
                yield return new WaitForSeconds(countdownInterval);
                s -= countdownInterval;
                Debug.Log("PreCount: " + s);
            }

            if (s == 0)
            {
                preCountActive = false;
                warningCountActive = true;
                WarningDialog(countdownLength);
            }
        }

        // WARNING DIALOG TIMER
        if (warningCountActive)
        {
            float s = seconds;
            while (s > 0)
            {
                yield return new WaitForSeconds(countdownInterval);
                if (timerDialogBoxInstance != null)
                    timerDialogCountdownTextTarget.text = s.ToString();
                s -= countdownInterval;
                Debug.Log("WarningCountdown: " + s);
            }

            if (s == 0)
                if (timerDialogBoxInstance != null)
                {
                    StopCoroutine(warningCounter);
                    Destroy(timerDialogBoxInstance);
                    RestartGame();
                }
        }
    }

    void StopTimerButton()
    {
        warningCountActive = false;
        StopCoroutine(warningCounter);

        if (timerDialogBoxInstance != null)
        {    
            Destroy(timerDialogBoxInstance);
            timerDialogBoxInstance = null;
        }
        Debug.Log("Restart Cancelled");
    }

    void ResetCountStates()
    {
        preCountActive = false;
        warningCountActive = false;
    }

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

1 个答案:

答案 0 :(得分:0)

脚本太长,无法找出问题,但我注意到可能存在问题。

WarningDialog函数中,查看以下代码块:

if (warningCountActive && !preCountActive && timerDialogBoxInstance != null)
{
    warningCounter = RunTimer(length); // create new reference to counter, resets countdown to countdownLength
    StartCoroutine(warningCounter);
}

StopTimerButton()函数可能无法正常工作,因为每次RunTimer函数仍在运行且您调用WarningDialog函数时,协程函数引用名为warningCounter丢失是因为当你warningCounter = RunTimer(length);时被覆盖。

您必须将warningCounter = RunTimer(length);移至Start()功能,以便warningCounter仅初始化一次

相关问题