public static class CoroutineManager
{
	private static Mono _mono;
	private static Mono Mono => EnsureMonoExists();
	
	private static Mono EnsureMonoExists()
	{
		if(_mono != null)
			return _mono;
		
		var obj = new GameObject("CoroutineManager");
		_mono = obj.AddComponent<Mono>();
		UnityEngine.Object.DontDestroyOnLoad(obj);
	}
	
	public static void StartInSequence<T>(T[] objects, Func<T, IEnumerator> routineGetter, float delay = 0, Action onComplete = null)
	{
		Mono.StartRoutine(InSequence(objects, routineGetter, delay), onComplete);
	}
	
	
	private static IEnumerator InSequence<T>(T[] objects, Func<T, IEnumerator> routineGetter, float delay)
	{
		WaitForSeconds wait = null;
		if(delay > 0)
			wait = new WaitForSeconds(delay);
		
		var running = 0;
		
		foreach(var obj in objects)
		{
			running++;
			_mono.StartRoutine(routineGetter.Invoke(obj), () => running--);
			
			if(delay > 0)
				yield return wait;
		}
		
		while(running > 0)
			yield return null;
		
	}
	
	private class Mono : MonoBehaviour
	{
		public void StartRoutine(IEnumerator routine, Action callback = null)
		{
			StartCoroutine(Routine(routine, callback));
		}
		
		public IEnumerator Routine(IEnumerator routine, Action callback)
		{
			yield return StartCoroutine(routine);
			callback?.Invoke();
		}
	}
}