StopCoroutine调用

时间:2017-07-20 20:25:18

标签: c# unity3d ienumerable

我似乎无法追查为什么会发生此错误..

MissingReferenceException:“Text”类型的对象已被销毁,但您仍在尝试访问它。 您的脚本应该检查它是否为null或者您不应该销毁该对象。

在调用StopTimerButton函数之后,似乎正在发生这种情况。之后,似乎我的RunTimer IEnumerator仍在运行。即使我在StopTimerButton()中调用StopCoroutine,RunTimer中的行 countdownTextTarget.text = s.ToString(); 仍然会被调用。这是为什么?需要一些帮助来追踪逻辑中断。谢谢!

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 countdownText;
    private Text countdownTextTarget;
    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

        if (timerDialogBoxInstance !=null)
        {
            timerDialogBoxInstance.transform.SetParent(canvas.transform, false);
            timerDialogBoxInstance.SetActive(true);

            countdownText = GameObject.FindGameObjectWithTag("CountdownText");
            countdownTextTarget = countdownText.GetComponent<Text>();

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

        if (warningCountActive && !preCountActive)
        {
            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 (!preCountActive && warningCountActive)
        {
            float s = seconds;
            while (s > 0)
            {
                yield return new WaitForSeconds(countdownInterval);
                countdownTextTarget.text = s.ToString();
                s -= countdownInterval;
                Debug.Log("WarningCountdown: " + s);
            }

            if (s == 0)
            {
                StopCoroutine(warningCounter);

                if (timerDialogBoxInstance)
                    Destroy(timerDialogBoxInstance);

                RestartGame();
            }
        }
    }

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

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

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

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

1 个答案:

答案 0 :(得分:2)

当您致电Destroy(timerDialogBoxInstance);并同时销毁countdownTextcountdownTextTarget(您在StopTimerButton()RunTimer()内执行此操作时)。

您应该在RunTimer()内检查(在访问Text对象之前)以查看对象是否已被销毁,如果是,请提前退出。

您可能还希望在销毁父变换后将变量设置为null。