using UnityEngine; using System; using System.Collections; /// /// A Sequence is a list of functions that are called successively. /// public class Sequence { #region Init /// /// Creates a new Sequence. /// /// The MonoBehaviour to run this on. /// public static Sequence Create(MonoBehaviour mb) { return new Sequence(mb); } private MonoBehaviour mb; private ArrayList items; private Invokeable finished; private bool isRunning; private Sequence(MonoBehaviour mb) { this.mb = mb; this.items = new ArrayList(); } #endregion #region Items /// /// A default function. /// public delegate void Invokeable(); /// /// Delegate function for an item that is asynchronous but not a coroutine. /// /// Should be called when the work is done. public delegate void AsyncInvokeable(Action done); /// /// Adds a normal function. /// /// The delegate function. /// This Sequence to allow for function chaining. public Sequence Push(Invokeable invoked) { items.Add(invoked); return this; } /// /// Adds an async function, which takes one parameter "done" which /// resolves this part of the sequence. /// /// The delegate function. /// This Sequence to allow for function chaining. public Sequence PushAsync(AsyncInvokeable invoked) { items.Add(invoked); return this; } /// /// Adds an IEnumerator which blocks the execution of the Sequence /// until it finishes it's work. /// /// The IEnumerator. /// This Sequence to allow for function chaining. public Sequence PushCoroutine(IEnumerator invoked) { items.Add(invoked); return this; } /// /// Adds a delay to the function execution. Execution is blocked for /// the given amount of seconds. /// /// The amount of seconds to block execution for. /// This Sequence to allow for function chaining. public Sequence Delay(float seconds) { items.Add(seconds); return this; } /// /// Sets a listener, which is called the Sequence has come to it's end. /// /// The delegate function. /// This Sequence to allow for function chaining. public Sequence OnFinish(Invokeable finished) { this.finished = finished; return this; } #endregion /// /// Starts this sequence. /// public void Play() { if (isRunning) { Debug.LogWarning("A sequence can't be started twice!"); return; } isRunning = true; mb.StartCoroutine(Invoke()); } #region Internal private IEnumerator Invoke() { Debug.Log("A Sequence has started."); if (items.Count > 0) { foreach (object item in items) { if (item is float) { float sec = (float)item; yield return new WaitForSeconds(sec); } else if (item is Invokeable) { Invokeable i = (Invokeable)item; i.Invoke(); } else if (item is AsyncInvokeable) { AsyncInvokeable ai = (AsyncInvokeable)item; yield return new AsyncYieldInstruction(ai); } else if (item is IEnumerator) { IEnumerator enumerator = (IEnumerator)item; yield return enumerator; } } // all items have been invoked isRunning = false; if (finished != null) { finished.Invoke(); } Debug.Log("A Sequence has ended."); } else { Debug.LogWarning("Can't play an empty Sequence!"); yield return null; } } /// /// Defines a YieldInstruction that returns when a "done" function is called. /// private class AsyncYieldInstruction : CustomYieldInstruction { public override bool keepWaiting { get { return !isDone; } } private bool isDone; public AsyncYieldInstruction(AsyncInvokeable invokeable) { invokeable(() => { this.isDone = true; }); } } #endregion }