Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 137 additions & 11 deletions Runtime/Utility/CountdownTimer.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace Zinnia.Utility
{
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Events;
using Zinnia.Extension;
Expand All @@ -10,6 +11,33 @@
/// </summary>
public class CountdownTimer : MonoBehaviour
{
/// <summary>
/// The source of Time to use.
/// </summary>
public enum TimeSourceType
{
/// <summary>
/// Taken from <see cref="Time.time"/>.
/// </summary>
ScaledTime,
/// <summary>
/// Taken from <see cref="Time.unscaledTime"/>.
/// </summary>
UnscaledTime,
/// <summary>
/// Taken from <see cref="Time.fixedTime"/>.
/// </summary>
FixedScaledTime,
/// <summary>
/// Taken from <see cref="Time.fixedUnscaledTime"/>.
/// </summary>
FixedUnscaledTime,
/// <summary>
/// Taken from <see cref="Time.realtimeSinceStartup"/>.
/// </summary>
RealTime
}

/// <summary>
/// Defines the event with the specified <see cref="float"/>.
/// </summary>
Expand Down Expand Up @@ -56,6 +84,25 @@ public bool BeginOnEnable
beginOnEnable = value;
}
}

[Tooltip("The source for the time to be used in the countdown.")]
[SerializeField]
private TimeSourceType timeSource;
/// <summary>
/// The source for the time to be used in the countdown.
/// </summary>
public TimeSourceType TimeSource
{
get
{
return timeSource;
}
set
{
timeSourceChanged = !timeSource.Equals(value);
timeSource = value;
}
}
#endregion

#region Timer Events
Expand Down Expand Up @@ -116,7 +163,7 @@ public float ElapsedTime
{
if (IsRunning && !IsPaused)
{
currentTime = Time.time;
currentTime = actualTime;
}
return currentTime - beginTime;
}
Expand All @@ -131,18 +178,18 @@ public float RemainingTime
{
if (IsRunning && !IsPaused)
{
currentTime = Time.time;
currentTime = actualTime;
}
return StartTime + (beginTime - currentTime);
}
}

/// <summary>
/// <see cref="Time.time"/> when <see cref="Begin"/> is called.
/// <see cref="actualTime"/> when <see cref="Begin"/> is called.
/// </summary>
protected float beginTime;
/// <summary>
/// <see cref="Time.time"/> of the current frame.
/// <see cref="actualTime"/> of the current frame.
/// </summary>
protected float currentTime;

Expand All @@ -151,6 +198,55 @@ public float RemainingTime
/// </summary>
protected float remainingAtPauseTime;

/// <summary>
/// Whether the <see cref="TimeSource"/> has changed.
/// </summary>
protected bool timeSourceChanged = true;

/// <summary>
/// The stored function for retrieving the time.
/// </summary>
protected Func<float> selectedTimeFunction = () => Time.time;

/// <summary>
/// The actual time value based on the selected <see cref="TimeSource"/>.
/// </summary>
protected float actualTime
{
get
{
if (timeSourceChanged)
{
switch(TimeSource)
{
case TimeSourceType.ScaledTime:
selectedTimeFunction = () => Time.time;
break;
case TimeSourceType.UnscaledTime:
selectedTimeFunction = () => Time.unscaledTime;
break;
case TimeSourceType.FixedScaledTime:
selectedTimeFunction = () => Time.fixedTime;
break;
case TimeSourceType.FixedUnscaledTime:
selectedTimeFunction = () => Time.fixedUnscaledTime;
break;
case TimeSourceType.RealTime:
selectedTimeFunction = () => Time.realtimeSinceStartup;
break;
}
timeSourceChanged = false;
}

return selectedTimeFunction();
}
}

/// <summary>
/// A container to hold the timer coroutine.
/// </summary>
protected Coroutine timerRoutine;

/// <summary>
/// Starts the timer counting down.
/// </summary>
Expand All @@ -171,10 +267,11 @@ public virtual void Begin()
/// </summary>
public virtual void Cancel()
{
CancelInvoke(nameof(Complete));
CancelRoutine();
//CancelInvoke(nameof(Complete));
if (IsRunning)
{
currentTime = Time.time;
currentTime = actualTime;
Cancelled?.Invoke();
IsRunning = false;
IsPaused = false;
Expand All @@ -194,7 +291,7 @@ public virtual void Pause()

remainingAtPauseTime = RemainingTime;
IsPaused = true;
CancelInvoke(nameof(Complete));
CancelRoutine();
Paused?.Invoke();
}

Expand Down Expand Up @@ -280,7 +377,36 @@ protected virtual void OnDisable()
protected virtual void StartTimer(float invokeTime)
{
SetInternalStates();
Invoke(nameof(Complete), invokeTime);
CancelRoutine();
timerRoutine = StartCoroutine(StartRoutine(invokeTime));
}

/// <summary>
/// Starts the timer routine.
/// </summary>
/// <param name="invokeTime">The time to wait until completion.</param>
/// <returns>The enumerator for the coroutine.</returns>
protected virtual IEnumerator StartRoutine(float invokeTime)
{
float targetTime = actualTime + invokeTime;
while (actualTime < targetTime)
{
yield return null;
}
Complete();
}

/// <summary>
/// Cancels the timer routine.
/// </summary>
protected virtual void CancelRoutine()
{
if (timerRoutine != null)
{
StopCoroutine(timerRoutine);
}

timerRoutine = null;
}

/// <summary>
Expand All @@ -294,12 +420,12 @@ protected virtual void Complete()
}

/// <summary>
/// Stores current <see cref="Time.time"/> for calculations.
/// Stores current <see cref="actualTime"/> for calculations.
/// </summary>
protected virtual void SetInternalStates()
{
beginTime = Time.time;
currentTime = Time.time;
beginTime = actualTime;
currentTime = actualTime;
}

/// <summary>
Expand Down
Loading