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
}