using System;
namespace Utility
{
///
/// An object that invokes an action after an amount of time has elapsed and
/// optionally continues repeating until told to stop.
///
public sealed class Timer
{
private static readonly Pool timers = new Pool(10, t => t.valid)
{
// Initialize is invoked whenever we get an instance through New()
Initialize = t =>
{
t.valid = true;
t.time = 0f;
},
// Deinitialize is invoked whenever an object is reclaimed during CleanUp()
Deinitialize = t =>
{
t.tick = null;
t.Tag = null;
}
};
private bool valid;
private float time;
private float tickLength;
private bool repeats;
private Action tick;
///
/// Gets or sets some extra data to the timer.
///
public object Tag { get; set; }
///
/// Gets whether or not this timer repeats.
///
public bool Repeats { get { return repeats; } }
///
/// Gets the length of time (in seconds) between ticks of the timer.
///
public float TickLength { get { return tickLength; } }
///
/// Creates a new Timer.
///
/// The amount of time between the timer's ticks.
/// Whether or not the timer repeats.
/// An action to perform when the timer ticks.
/// The new Timer object or null if the timer pool is full.
public static Timer Create(float tickLength, bool repeats, Action tick)
{
if (tickLength <= 0f)
throw new ArgumentException("tickLength must be greater than zero.");
if (tick == null)
throw new ArgumentNullException("tick");
// get a new timer from the pool
Timer t = timers.New();
t.tickLength = tickLength;
t.repeats = repeats;
t.tick = tick;
return t;
}
///
/// Stops the timer.
///
public void Stop()
{
valid = false;
}
///
/// Updates all the Timers.
///
/// The elapsed time (in seconds) to advance the timers. Generally you want to pass in (float)gameTime.ElapsedGameTime.TotalSeconds from your main Game class.
public static void Update(float dt)
{
for (int i = 0; i < timers.ValidCount; i++)
{
Timer t = timers[i];
// if a timer is stopped manually, it may not
// be valid at this point so we skip it.
if (!t.valid)
continue;
// update the timer's time
t.time += dt;
// if the timer passed its tick length...
if (t.time >= t.tickLength)
{
// perform the action
t.tick(t);
// subtract the tick length in case we need to repeat
t.time -= t.tickLength;
// if the timer doesn't repeat, it is no longer valid
if (!t.repeats)
t.valid = false;
}
}
// clean up any invalid timers
timers.CleanUp();
}
}
}