|
using UnityEngine; |
|
using System; |
|
using System.Collections; |
|
|
|
/// <summary> |
|
/// A Sequence is a list of functions that are called successively. |
|
/// </summary> |
|
public class Sequence |
|
{ |
|
#region Init |
|
|
|
/// <summary> |
|
/// Creates a new Sequence. |
|
/// </summary> |
|
/// <param name="mb">The MonoBehaviour to run this on.</param> |
|
/// <returns></returns> |
|
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 |
|
|
|
/// <summary> |
|
/// A default function. |
|
/// </summary> |
|
public delegate void Invokeable(); |
|
|
|
/// <summary> |
|
/// Delegate function for an item that is asynchronous but not a coroutine. |
|
/// </summary> |
|
/// <param name="done">Should be called when the work is done.</param> |
|
public delegate void AsyncInvokeable(Action done); |
|
|
|
/// <summary> |
|
/// Adds a normal function. |
|
/// </summary> |
|
/// <param name="invoked">The delegate function.</param> |
|
/// <returns>This Sequence to allow for function chaining.</returns> |
|
public Sequence Push(Invokeable invoked) |
|
{ |
|
items.Add(invoked); |
|
return this; |
|
} |
|
|
|
/// <summary> |
|
/// Adds an async function, which takes one parameter "done" which |
|
/// resolves this part of the sequence. |
|
/// </summary> |
|
/// <param name="invoked">The delegate function.</param> |
|
/// <returns>This Sequence to allow for function chaining.</returns> |
|
public Sequence PushAsync(AsyncInvokeable invoked) |
|
{ |
|
items.Add(invoked); |
|
return this; |
|
} |
|
|
|
/// <summary> |
|
/// Adds an IEnumerator which blocks the execution of the Sequence |
|
/// until it finishes it's work. |
|
/// </summary> |
|
/// <param name="invoked">The IEnumerator.</param> |
|
/// <returns>This Sequence to allow for function chaining.</returns> |
|
public Sequence PushCoroutine(IEnumerator invoked) |
|
{ |
|
items.Add(invoked); |
|
return this; |
|
} |
|
|
|
/// <summary> |
|
/// Adds a delay to the function execution. Execution is blocked for |
|
/// the given amount of seconds. |
|
/// </summary> |
|
/// <param name="seconds">The amount of seconds to block execution for.</param> |
|
/// <returns>This Sequence to allow for function chaining.</returns> |
|
public Sequence Delay(float seconds) |
|
{ |
|
items.Add(seconds); |
|
return this; |
|
} |
|
|
|
/// <summary> |
|
/// Sets a listener, which is called the Sequence has come to it's end. |
|
/// </summary> |
|
/// <param name="finished">The delegate function.</param> |
|
/// <returns>This Sequence to allow for function chaining.</returns> |
|
public Sequence OnFinish(Invokeable finished) |
|
{ |
|
this.finished = finished; |
|
return this; |
|
} |
|
|
|
#endregion |
|
|
|
/// <summary> |
|
/// Starts this sequence. |
|
/// </summary> |
|
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; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Defines a YieldInstruction that returns when a "done" function is called. |
|
/// </summary> |
|
private class AsyncYieldInstruction : CustomYieldInstruction |
|
{ |
|
public override bool keepWaiting |
|
{ |
|
get |
|
{ |
|
return !isDone; |
|
} |
|
} |
|
|
|
private bool isDone; |
|
|
|
public AsyncYieldInstruction(AsyncInvokeable invokeable) |
|
{ |
|
invokeable(() => { |
|
this.isDone = true; |
|
}); |
|
} |
|
} |
|
|
|
#endregion |
|
} |