StopCoroutine 调用后文本对象更新

Text object updating after StopCoroutine called

我似乎无法找出为什么会出现此错误。

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

这似乎是在调用 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);
    }
}

当您调用 Destroy(timerDialogBoxInstance); 时,也会破坏 countdownTextcountdownTextTarget(您在 StopTimerButton()RunTimer() 中执行)。

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

您可能还想在销毁其父转换后将变量设置为空。