问题
I'm getting an error message and I'm not exactly sure how to solve. I'm trying to start a countdown after a short period of idleness that then kicks off a second countdown that is paired with a visual warning. As soon as the coroutine kicks on I'm getting this error:
Coroutine couldn't be started because the the game object '_CountdownTimer' is inactive! UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator) CountdownTimer:StartPreCountTimer() (at Assets/_Components/_Scripts/CountdownTimer.cs:38) GameManager:CheckUserActivity() (at Assets/_Components/_Scripts/GameManager.cs:68)
What am I missing? Where would I need to set the active state of _CountdownTimer? Thank you!!
GameManager.cs
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour
{
public static GameManager gameManagerInstance = null; // Create Singleton
public float checkUserActivityInterval;
public GameObject loader;
public GameObject countdownTimer;
private GameObject gameManager;
private Vector3 currentMousePosition;
private Vector3 prevMousePosition;
private CountdownTimer countdownInstance;
private Scene currentScene;
public Color defaultBackgroundColor;
public Object startingScene;
public static bool userActive;
public static bool preCountActive;
public static bool restartWarningActive;
public static string animalDataFilePathJSON;
public static string animalDataFilePathTex;
void Awake ()
{
if (CountdownTimer.countdownTimerInstance == null)
Instantiate(countdownTimer);
if (gameManagerInstance == null)
gameManagerInstance = this;
else if (gameManagerInstance != null)
Destroy(gameObject);
DontDestroyOnLoad(gameObject);
}
void Start()
{
prevMousePosition = Input.mousePosition;
countdownInstance = countdownTimer.GetComponent<CountdownTimer>(); // Create an instance of CountdownTimer
InvokeRepeating("CheckUserActivity", 0, checkUserActivityInterval);
InvokeRepeating("SetPrevMousePosition", 0, checkUserActivityInterval);
}
void Update()
{
currentScene = SceneManager.GetActiveScene();
currentMousePosition = Input.mousePosition;
}
void CheckUserActivity()
{
if (currentScene.name != startingScene.name)
{
if (currentMousePosition == prevMousePosition)
{
Debug.Log("MOUSE HAS NOT MOVED!!");
userActive = false;
if (!userActive && !preCountActive)
countdownInstance.StartPreCountTimer();
}
if (currentMousePosition != prevMousePosition)
{
Debug.Log("MOUSE HAS MOVED!!");
userActive = true;
if (preCountActive == true)
countdownInstance.RestartPreCountTimer();
}
}
}
void SetPrevMousePosition()
{
prevMousePosition = Input.mousePosition;
}
}
CountdownTimer.cs
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;
private GameObject timerDialogBoxInstance;
private GameObject canvas;
private IEnumerator counter;
private Button stopCountButton;
private Text timerTextField;
public float countdownLength;
public float countdownDelay;
private float countdownInterval = 1;
void Awake()
{
if (countdownTimerInstance == null)
countdownTimerInstance = this;
else if (countdownTimerInstance != null)
Destroy(gameObject);
DontDestroyOnLoad(gameObject);
}
public void StartPreCountTimer()
{
GameManager.preCountActive = true;
GameManager.restartWarningActive = false;
counter = RunTimer(countdownDelay); // create new reference to counter
StartCoroutine(counter);
}
public void RestartPreCountTimer()
{
GameManager.preCountActive = false;
StopTimer();
}
void ShowRestartWarning()
{
GameManager.preCountActive = false;
GameManager.restartWarningActive = true;
canvas = GameObject.FindGameObjectWithTag("Canvas");
timerDialogBoxInstance = Instantiate(timeOutWarningDialog); // instantiate timeout warning dialog
timerDialogBoxInstance.transform.SetParent(canvas.transform, false);
timerDialogBoxInstance.SetActive(true);
Text[] textFields = timerDialogBoxInstance.GetComponentsInChildren<Text>(true); // get reference to timer textfields
timerTextField = textFields[2]; // access and assign countdown textfield
stopCountButton = timerDialogBoxInstance.GetComponentInChildren<Button>(); // get reference to keep playing button
stopCountButton.onClick.AddListener(StopTimer); // add button listener
if (timerDialogBoxInstance.activeInHierarchy == true)
{
counter = RunTimer(countdownLength); // create new reference to counter, resets countdown to countdownLength
StartCoroutine(counter);
}
}
IEnumerator RunTimer(float seconds)
{
float s = seconds;
while (s > -1)
{
if (GameManager.restartWarningActive == true)
if (timerTextField != null)
timerTextField.text = s.ToString();
yield return new WaitForSeconds(countdownInterval);
s -= countdownInterval;
}
if (s == -1)
{
if (GameManager.restartWarningActive == true)
RestartGame();
}
}
void StopTimer()
{
Debug.Log("Restart Cancelled");
StopCoroutine(counter);
Destroy(timerDialogBoxInstance);
}
void RestartGame()
{
SceneManager.LoadScene(startingScene.name);
}
}
回答1:
I think I know where your error is. When you create an instance of the countdownTimer
. You have to store a reference to it in order to get the underlying CountdownTimer class.
Try doing this, in your GameManager Class
private GameObject countDownTimerInstance;
Awake()
countDownTimerInstance = Instantiate(countdownTimer);
and in the Start() do,
countdownInstance = countdownTimerInstance.GetComponent<CountdownTimer>();
I think the problem was you were directly accessing the prefab's getComponent() instead of the instantiated gameObject's CountdownTimer!.
来源:https://stackoverflow.com/questions/45135385/coroutine-not-starting-due-to-inactive-game-object