/// <summary> /// Creates a command which runs a coroutine. /// </summary> /// <param name='command'> /// The command to generate the coroutine. /// </param> /// <remarks> /// The reason this method doesn't just except an IEnumerator is that /// IEnumerators created from continuations can't be reset, (a continuation is /// any method containing a yield statement, and returning an IEnumerator). This means /// that coroutines would break when executed within a repeat command. /// By encapsulating the call to create the IEnumerator in a delegate, it is possible for a /// user to call the coroutine however they please, and for it to be repeatable. /// </remarks> /// <example> /// <code> /// private CommandQueue _queue = new CommandQueue(); /// /// IEnumerator<CommandDelegate> CoroutineMethod(int firstVal, int secondVal, int thirdVal) /// { /// Debug.Log(firstVal); /// yield return Commands.WaitForSeconds(1.0f); // You can return any CommandDelegate here. /// Debug.Log(secondVal); /// yield return null; // Wait a single frame. /// Debug.Log(thirdVal); /// yield break; // Force exits the coroutine. /// } /// /// IEnumerator<CommandDelegate> CoroutineNoArguments() /// { /// yield return Commands.WaitForSeconds(2.0); /// } /// /// void Start() /// { /// _queue.Enqueue( /// Commands.Coroutine( () => CoroutineMethod(1,2,3)), /// Commands.Coroutine(CoroutineNoArguments) /// ); /// } /// /// void Update() /// { /// _queue.Update(Time.deltaTime); /// } /// /// </code> /// </example> public static CommandDelegate Coroutine(CommandCoroutine command) { CheckArgumentNonNull(command); IEnumerator <CommandDelegate> coroutine = null; CommandDelegate currentCommand = null; return((ref double deltaTime) => { // Create our coroutine, if we don't have one. if (coroutine == null) { coroutine = command(); // Finish if we couldn't create a coroutine. if (coroutine == null) { return true; } } bool finished = true; while (finished) { // Set the current command. if (currentCommand == null) { if (!coroutine.MoveNext()) { coroutine = null; return true; } currentCommand = coroutine.Current; if (currentCommand == null) { // Yield return null will wait a frame, like with // Unity coroutines. currentCommand = Commands.WaitForFrames(1); } } finished = currentCommand(ref deltaTime); if (finished) { currentCommand = null; } } return false; }); }
/// <summary> /// Creates a command which runs a coroutine. /// </summary> /// <param name='command'> /// The command to generate the coroutine. /// </param> /// <remarks> /// The reason this method doesn't just except an IEnumerator is that /// IEnumerators created from continuations can't be reset, (a continuation is /// any method containing a yield statement, and returning an IEnumerator). This means /// that coroutines would break when executed within a repeat command. /// By encapsulating the call to create the IEnumerator in a delegate, it is possible for a /// user to call the coroutine however they please, and for it to be repeatable. /// </remarks> /// <example> /// <code> /// private CommandQueue _queue = new CommandQueue(); /// /// IEnumerator<CommandDelegate> CoroutineMethod(int firstVal, int secondVal, int thirdVal) /// { /// Debug.Log(firstVal); /// yield return Commands.WaitForSeconds(1.0f); // You can return any CommandDelegate here. /// Debug.Log(secondVal); /// yield return null; // Wait a single frame. /// Debug.Log(thirdVal); /// yield break; // Force exits the coroutine. /// } /// /// IEnumerator<CommandDelegate> CoroutineNoArguments() /// { /// yield return Commands.WaitForSeconds(2.0); /// } /// /// void Start() /// { /// _queue.Enqueue( /// Commands.Coroutine( () => CoroutineMethod(1,2,3)), /// Commands.Coroutine(CoroutineNoArguments) /// ); /// } /// /// void Update() /// { /// _queue.Update(Time.deltaTime); /// } /// /// </code> /// </example> public static CommandDelegate Coroutine(CommandCoroutine command) { CheckArgumentNonNull(command); IEnumerator<CommandDelegate> coroutine = null; CommandDelegate currentCommand = null; return (ref double deltaTime) => { // Create our coroutine, if we don't have one. if (coroutine == null) { coroutine = command(); // Finish if we couldn't create a coroutine. if (coroutine == null) { return true; } } bool finished = true; while (finished) { // Set the current command. if (currentCommand == null) { if (!coroutine.MoveNext()) { coroutine = null; return true; } currentCommand = coroutine.Current; if (currentCommand == null) { // Yield return null will wait a frame, like with // Unity coroutines. currentCommand = Commands.WaitForFrames(1); } } finished = currentCommand(ref deltaTime); if (finished) { currentCommand = null; } } return false; }; }