How can I stop coroutine from another script file?

I have read the answers already given for similar problems but unable to find a solution. I have a coroutine in one script file, which I want to stop from another script file based on certain condition. Please guide me what I’m doing wrong. I have little experience with Unity.
I’m getting this message when I play the game:
“NullReferenceException: Object reference not set to an instance of an object
GameController.Start () (at Assets/Scripts/GameController.cs:18)”.

First script with the start coroutine is this:

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

public class GameController : MonoBehaviour {

	public Camera cam;
	public GameObject[] balls;
	private float maxWidth;

	// Use this for initialization
	void Start () {
		if (cam == null) {
			cam = Camera.main;
		}
		Vector3 upperCorner = new Vector3(Screen.width, Screen.height, 0.0f);
		Vector3 targetWidth = cam.ScreenToWorldPoint(upperCorner);
		float ballWidth = balls[0].GetComponent<Renderer> ().bounds.extents.x;
		maxWidth = targetWidth.x - ballWidth;
		StartCoroutine (Spawn ());

	}
	
	public IEnumerator Spawn () {
		yield return new WaitForSeconds (2.0f); 
		while (true) {
			GameObject ball = balls [Random.Range (0, balls.Length)];
			Vector3 spawnPosition = new Vector3 (Random.Range (-maxWidth, maxWidth), transform.position.y, 0.0f);
			Quaternion spawnRotation = Quaternion.identity;
			Instantiate (ball, spawnPosition, spawnRotation);
			yield return new WaitForSeconds (Random.Range (1.0f, 2.0f));
		}

	}

	public void GameEnd () {

		StopCoroutine (Spawn ());
	
	}
}

and the script from where I’m trying to stop it is this:

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

public class DestroyOnContact : MonoBehaviour {

	public GameObject gameOverText;
	public GameObject restartButton;



	void OnTriggerEnter2D (Collider2D other) {
		if (other.gameObject.tag != "Zero")
		{
			StartCoroutine (GameOver ());
		}
			
		GameController gc = gameObject.AddComponent<GameController> ();
		gc.GameEnd ();
		Destroy (other.gameObject);
	}

	IEnumerator GameOver () {

		yield return new WaitForSeconds (1.0f);
		gameOverText.SetActive (true);
		restartButton.SetActive (true);
	}

}

1 Answer

1

This will never work:

StopCoroutine (Spawn ());

When you call “Spawn()” it returns a statemachine object which you initially pass to StartCoroutine. Here when you call Spawn again you create a new seperate object which doesn’t run as a coroutine. So StopCoroutine can’t stop anything.

You have to save your “Coroutine” instance when you create it and use that in StopCoroutine:

private Coroutine gameCoroutine = null;


void Start()
{
    // [ ... ]
    gameCoroutine = StartCoroutine (Spawn ());
}

public void GameEnd ()
{
    if (gameCoroutine != null)
        StopCoroutine (gameCoroutine);
}

@Bunny83 Thanks for taking time to explain. I've tried the solution you provided but unfortunately, I'm still getting the same error message and the coroutine does not stop when called from second script using "gc.GameEnd();" as the balls continue to fall. Do I need to somehow change the code in the other script too?

@Bunny83 Your solution finally worked for me. Thanks a lot. It was my mistake not to have attached "Public GameController" to "DestroyOnContact" in the inspector. When I did, it worked.

Oh, when I do pod install manually, the .xcworkspace is generated fine. I meant that it isn't generated by default in the Unity build. I suppose there is nothing wrong with that. The problem is that when I open this .xcworspace file and build it from there, I get several 'not found' errors. I have also tried to find which files (or classes?) are missing and adding their pods. I reached a point where I was getting a 'not found' error for some files I couldn't find the pods for.