C#, some kind of coroutine that can pause?

Hi! I’d like to have some kind of tool to let me determine when an action will be triggered (in frames is the best way for me), there is the StartCoroutine that seems to work, but I can only use it with seconds and I cannot pause and resume this coroutine. Anyone has an idea on how to make something as easy to implement as the coroutine, but that would support frames and stop/resume?

You can absolutely do that with a coroutine - here is an example using a helper function to make it easier to control.

#DelayedExecution.cs#

public static class DelayedExecution
{
    public static void StartCoroutine(this GameObject gameObject, IEnumerator coroutine)
    {
      var behaviour = gameObject.GetComponent<CoroutineHelper>();
      if(!behaviour)
           behaviour = gameObject.AddComponent<CoroutineHelper>();
      behaviour.StartCoroutine(coroutine);
    }

    public class CoroutineHelper : MonoBehaviour {}

	public class WaitController
	{
		public bool cancel;
		public bool pause;
	}

	static IEnumerator WaitForANumberOfFrames(int numberOfFrames, Action thingToDo, WaitController controller)
	{
		while(numberOfFrames > 0)
		{
			if(!controller.pause)
				numberOfFrames--;
			if(controller.cancel)
				yield break;
			yield return null;
		}
		thingToDo();
	}

	static IEnumerator WaitForAPeriodOfTime(float timeToWait, Action thingToDo, WaitController controller)
	{
		while(timeToWait > 0)
		{
			if(!controller.pause)
				timeToWait -= Time.deltaTime;
			if(controller.cancel)
				yield break;
			yield return null;
		}
		thingToDo();
	}
    
	public static WaitController DoSomethingLater(this GameObject gameObject, Action thingToDo, int numberOfFrames)
	{
		var controller = new WaitController();
		gameObject.StartCoroutine(WaitForANumberOfFrames(numberOfFrames, thingToDo, controller));
		return controller;
	}
	public static WaitController DoSomethingLater(this GameObject gameObject, Action thingToDo, float timeToWait)
	{
		var controller = new WaitController();
		gameObject.StartCoroutine(WaitForAPeriodOfTime(timeToWait, thingToDo, controller));
		return controller;
	}
    public static WaitController DoSomethingLater(this MonoBehaviour behaviour, Action thingToDo, int numberOfFrames)
	{
		var controller = new WaitController();
		behaviour.StartCoroutine(WaitForANumberOfFrames(numberOfFrames, thingToDo, controller));
		return controller;
	}
	public static WaitController DoSomethingLater(this MonoBehaviour behaviour, Action thingToDo, float timeToWait)
	{
		var controller = new WaitController();
		behaviour.StartCoroutine(WaitForAPeriodOfTime(timeToWait, thingToDo, controller));
		return controller;
	}

}

That’s a static utility class - you would use if from your code like this:

#TestIt.cs#

public class TestIt : MonoBehaviour
{
	public DelayedExecution.WaitController controller;
	
	void Start()
	{
		//Either
		controller = gameObject.DoSomethingLater(DisplayMessage, 15);
		//Or
		controller = gameObject.DoSomethingLater(()=>{
			//You can execute anything you like here e.g.
			Destroy(gameObject);
		}, 20);
            //Or to wait for a period of time instead
             controller = gameObject.DoSomethingLater(DisplayMessage, 5f); //Use a float to wait for time and an int for frames
	}
	
	void Update()
	{
		if(Input.GetKeyDown(KeyCode.P))
		{
			controller.pause = !controller.pause;
		}
	}
	
	void DisplayMessage()
	{
		//Do something here
	}
}