TimerKit is a versatile, easy-to-use timer component designed for Unity
Whether you're building a countdown for a game level, managing cooldowns, or triggering events at specific intervals, TimerKit provides a robust solution. It combines basic timing functionality with advanced features, all wrapped in an extensible and Unity-friendly design.
- Basic Operations: Start, stop, reset, and query the timer's state.
- Pause & Resume: Pause the timer and pick up where you left off.
- Fast Forward & Rewind: Skip ahead or backtrack through time.
- Milestones: Trigger custom actions at specific time or progress points.
- Range Milestones: Trigger events at regular intervals within a time range.
- Serialization: Save and load timer states for persistent gameplay.
- Unity Integration: Works seamlessly as a MonoBehaviour or standalone class.
- Extensible Architecture: Multiple timer classes for different complexity needs.
- Service Locator Support: Optional integration with dependency injection patterns.
Add the TimerKit package to your Unity project via the Unity Package Manager:
- Open the Package Manager (
Window > Package Manager
). - Click the + button and select "Add package from git URL".
- Enter:
https://github.com/PaulNonatomic/TimerKit.git
. - Click Add.
The package provides a flexible hierarchy of timer classes to suit different needs:
BasicTimer
: Pure timer functionality without milestone support (~150 lines)MilestoneTimer
: Extends BasicTimer with milestone supportStandardTimer
: Full-featured timer with all capabilities (recommended for new projects)Timer
: Unity MonoBehaviour wrapper for Unity integrationSimpleTimer
: [DEPRECATED] Alias for StandardTimer (maintained for backward compatibility)
IReadOnlyTimer
: Read-only timer properties (TimeRemaining, TimeElapsed, Progress, etc.)IBasicTimer
: Basic timer operations extending IReadOnlyTimerITimer
: Full timer functionality with milestone management
For Unity integration with Inspector support:
using Nonatomic.TimerKit;
using UnityEngine;
public class CountdownExample : MonoBehaviour
{
private Timer _timer;
void Start()
{
_timer = gameObject.AddComponent<Timer>();
_timer.Duration = 30f; // 30 seconds
_timer.OnComplete += () => Debug.Log("Countdown finished!");
_timer.StartTimer();
}
}
For pure C# usage without Unity dependencies:
using Nonatomic.TimerKit;
public class StandaloneExample
{
private StandardTimer _timer;
public void StartCountdown()
{
_timer = new StandardTimer(30f); // 30 seconds
_timer.OnComplete += () => Console.WriteLine("Countdown finished!");
_timer.StartTimer();
// In your update loop:
// _timer.Update(deltaTime);
}
}
// Create a timer
var timer = new StandardTimer(10f); // 10 second duration
// Control the timer
timer.StartTimer(); // Start from full duration
timer.ResumeTimer(); // Resume from current position
timer.StopTimer(); // Pause the timer
timer.ResetTimer(); // Reset to full duration
// Time manipulation
timer.FastForward(2f); // Skip ahead 2 seconds
timer.Rewind(1f); // Go back 1 second
// Query timer state
bool isRunning = timer.IsRunning;
float timeLeft = timer.TimeRemaining;
float elapsed = timer.TimeElapsed;
float progress = timer.ProgressElapsed; // 0.0 to 1.0
timer.OnStart += () => Debug.Log("Timer started");
timer.OnResume += () => Debug.Log("Timer resumed");
timer.OnStop += () => Debug.Log("Timer stopped");
timer.OnComplete += () => Debug.Log("Timer completed");
timer.OnTick += (IReadOnlyTimer t) => Debug.Log($"Time: {t.TimeRemaining}");
Milestones trigger callbacks when the timer reaches specific points:
// Basic milestone - trigger at 5 seconds remaining
var milestone = new TimerMilestone(TimeType.TimeRemaining, 5f, () => {
Debug.Log("5 seconds left!");
});
timer.AddMilestone(milestone);
// Progress-based milestone - trigger at 75% completion
var progressMilestone = new TimerMilestone(TimeType.ProgressElapsed, 0.75f, () => {
Debug.Log("75% complete!");
});
timer.AddMilestone(progressMilestone);
// Remove milestones
timer.RemoveMilestone(milestone);
timer.RemoveAllMilestones();
timer.RemoveMilestonesByCondition(m => m.TriggerValue < 3f);
Range milestones trigger at regular intervals within a specified range:
// Trigger every second for the last 10 seconds
var rangeMilestone = timer.AddRangeMilestone(
TimeType.TimeRemaining, // Type of time to track
10f, // Range start (10 seconds remaining)
0f, // Range end (0 seconds remaining)
1f, // Interval (every 1 second)
() => Debug.Log("Countdown warning!") // Callback
);
// Trigger every 0.5 seconds from 2-5 seconds elapsed
timer.AddRangeMilestone(
TimeType.TimeElapsed,
2f, // Start at 2 seconds elapsed
5f, // End at 5 seconds elapsed
0.5f, // Every 0.5 seconds
() => PlayTickSound() // Callback
);
TimeRemaining
: Time left on the timer (countdown)TimeElapsed
: Time passed since timer startedProgressElapsed
: Completion progress (0.0 to 1.0)ProgressRemaining
: Remaining progress (1.0 to 0.0)
public class LevelTimer : MonoBehaviour
{
private Timer _timer;
void Start()
{
_timer = gameObject.AddComponent<Timer>();
_timer.Duration = 300f; // 5 minutes
// Add warning milestones
_timer.AddMilestone(new TimerMilestone(TimeType.TimeRemaining, 60f, () =>
ShowWarning("1 minute remaining!")));
_timer.AddMilestone(new TimerMilestone(TimeType.TimeRemaining, 30f, () =>
ShowWarning("30 seconds remaining!")));
// Add countdown for last 10 seconds
_timer.AddRangeMilestone(TimeType.TimeRemaining, 10f, 0f, 1f, () =>
PlayCountdownBeep());
_timer.OnComplete += () => EndLevel();
_timer.StartTimer();
}
}
public class AbilityCooldown : MonoBehaviour
{
[SerializeField] private float _cooldownDuration = 5f;
private Timer _cooldownTimer;
void Start()
{
_cooldownTimer = gameObject.AddComponent<Timer>();
_cooldownTimer.Duration = _cooldownDuration;
_cooldownTimer.OnComplete += () => OnCooldownComplete();
}
public void UseAbility()
{
if (_cooldownTimer.IsRunning) return; // Still on cooldown
// Execute ability logic here
Debug.Log("Ability used!");
// Start cooldown
_cooldownTimer.StartTimer();
}
private void OnCooldownComplete()
{
Debug.Log("Ability ready!");
}
public float GetCooldownProgress() => _cooldownTimer.ProgressElapsed;
}
When the SERVICE_LOCATOR
preprocessor directive is defined, you can use dependency injection:
// Custom timer service
public class GameTimerService : BaseTimerService<IGameTimerService>
{
// Your custom timer logic here
}
// Register and use
ServiceLocator.Register<IGameTimerService>(gameTimerService);
var timerService = ServiceLocator.Get<IGameTimerService>();
If you're using the deprecated SimpleTimer
class:
Before:
var timer = new SimpleTimer(10f);
After:
var timer = new StandardTimer(10f);
The API is identical, but StandardTimer
provides better clarity about the class's capabilities.
- Use
BasicTimer
when you only need start/stop/reset functionality - Use
MilestoneTimer
when you need milestone support but want a lighter class - Use
StandardTimer
for full functionality (recommended for most use cases) - Use
Timer
(MonoBehaviour) for Unity Inspector integration
SimpleTimer
has been deprecated in favor of StandardTimer
. This is not a breaking change - all existing code continues to work unchanged, but you'll see compiler warnings.
SimpleTimer
class - UseStandardTimer
instead
- All existing APIs remain identical - no code changes required
- Full backward compatibility maintained
- All existing functionality preserved
// Old (still works, but shows deprecation warning)
var timer = new SimpleTimer(10f);
// New (recommended for new code)
var timer = new StandardTimer(10f);
The new class hierarchy provides better separation of concerns:
- Smaller classes for specific needs (BasicTimer for simple cases)
- Clearer intent with descriptive names (StandardTimer vs SimpleTimer)
- Better extensibility with proper inheritance chain
Existing projects can continue using SimpleTimer
without any changes. The deprecation warning can be suppressed if needed:
#pragma warning disable CS0618 // Type or member is obsolete
var timer = new SimpleTimer(10f);
#pragma warning restore CS0618