Skip to content

Commit 801143b

Browse files
committed
Optimzed milestones. Updated README and added some additional tests.
1 parent 51a82bc commit 801143b

14 files changed

Lines changed: 104 additions & 91 deletions

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
# Change Log
22

3+
## [0.1.0-beta] - Feb 26, 2025
4+
- Optimized Milstones
5+
- Added additional test for Milestone removal
6+
- Adjust namespace to be more consistent with other Nonatomic packages
7+
38
## [0.0.0-beta] - Sept 28, 2024
49
- First commit

README.md

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,43 @@
1-
# Timers #
1+
# Timers
22

3-
## Overview ##
4-
Timer is a versatile, easy-to-use timer component designed for Unity projects. It supports basic timing operations like start, stop, and reset, along with advanced features such as pausing, resuming, fast forwarding, rewinding, and handling milestones that trigger custom actions.
3+
## Overview
4+
**Timers** is a versatile, easy-to-use timer component designed for Unity projects. Whether you’re building a countdown for a game level, managing cooldowns, or triggering events at specific intervals, this package provides a robust solution. It combines basic timing functionality with advanced features, all wrapped in an extensible and Unity-friendly design.
55

66
### Features
7-
- Basic Timer Operations: Start, stop, and reset the timer.
8-
- Pause and Resume: Pause the timer and resume from the last stopped point without resetting.
9-
- Fast Forward and Rewind: Jump forward or backward in time.
10-
- **Milestones:** Set up callbacks to execute when the timer reaches certain points.
11-
- **Serialization:** Serialize and deserialize the timer's state, useful for game saves.
12-
- **Extensible:** Easy to extend with additional features and integrate into larger systems.
13-
14-
## Installation ##
15-
To install the Timers package in your Unity project, follow these steps:
16-
17-
1. Open Unity and navigate to the Package Manager.
18-
- Click on the + button and select Add package from git URL...
19-
- Enter the following URL: https://github.com/PaulNonatomic/Timer and press Add.
20-
2. Add the Timer component onto any active GameObject in your scene, or create a new GameObject dedicated to the timer.
21-
22-
## Usage ##
23-
24-
## API Reference ##
25-
* StartTimer(): Start or restart the timer.
26-
* StopTimer(): Pause the timer.
27-
* ResetTimer(): Reset the timer to its initial state.
28-
* ResumeTimer(): Resume the timer from the last paused state.
29-
* FastForward(float seconds): Advance the timer by a specified number of seconds.
30-
* Rewind(float seconds): Reverse the timer by a specified number of seconds.
31-
* AddMilestone(TimerMilestone milestone): Add a milestone that triggers a callback when reached.
32-
* RemoveMilestone(TimerMilestone milestone): Remove a milestone from the timer.
33-
* ClearMilestones(): Clears all milestones from the timer, ceasing any pending triggers.
34-
* RemoveMilestonesByCondition(Predicate<TimerMilestone> condition): Removes a specific milestone from the timer.
35-
36-
## Contributing ##
37-
Contributions are welcome! Please refer to CONTRIBUTING.md for guidelines on how to contribute.
38-
39-
## License ##
40-
The Timers package is licensed under the MIT license. See LICENSE for more details.
7+
- **Basic Operations**: Start, stop, reset, and query the timer’s state.
8+
- **Pause & Resume**: Pause the timer and pick up where you left off.
9+
- **Fast Forward & Rewind**: Skip ahead or backtrack through time.
10+
- **Milestones**: Trigger custom actions at specific time or progress points.
11+
- **Serialization**: Save and load timer states for persistent gameplay.
12+
- **Unity Integration**: Works seamlessly as a MonoBehaviour or standalone class.
13+
- **Extensible**: Virtual methods and interfaces make customization a breeze.
14+
15+
## Installation
16+
Add the Timers package to your Unity project via the Unity Package Manager:
17+
18+
1. Open the Package Manager (`Window > Package Manager`).
19+
2. Click the **+** button and select **"Add package from git URL"**.
20+
3. Enter: `https://github.com/PaulNonatomic/Timer.git`.
21+
4. Click **Add**.
22+
23+
## Usage
24+
Below are some practical examples to get you started with Timers in your Unity project.
25+
26+
### Example 1: Simple Countdown
27+
Create a 30-second countdown that logs when it’s done.
28+
```csharp
29+
using Timers.Runtime;
30+
using UnityEngine;
31+
32+
public class CountdownExample : MonoBehaviour
33+
{
34+
private Timer _timer;
35+
36+
void Start()
37+
{
38+
_timer = gameObject.AddComponent<Timer>();
39+
_timer.Duration = 30f; // 30 seconds
40+
_timer.OnComplete += () => Debug.Log("Countdown finished!");
41+
_timer.StartTimer();
42+
}
43+
}

Runtime/IReadOnlyTimer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace Timers.Runtime
1+
namespace Nonatomic.Timers
22
{
33
public interface IReadOnlyTimer
44
{

Runtime/ITimer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System;
22

3-
namespace Timers.Runtime
3+
namespace Nonatomic.Timers
44
{
55
/// <summary>
66
/// Defines a contract for timer functionality, allowing for starting, stopping, and resetting the timer,

Runtime/SimpleTimer.cs

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
using System;
22
using System.Collections.Generic;
33
using UnityEngine;
4-
using UnityEngine.UIElements;
54

6-
namespace Timers.Runtime
5+
namespace Nonatomic.Timers
76
{
87
/// <summary>
98
/// Implements a basic countdown timer with start, stop, reset, fast forward, and rewind capabilities,
@@ -39,7 +38,7 @@ public float Duration
3938

4039
private float _duration;
4140
private bool _isRunning;
42-
private List<TimerMilestone> _milestones = new List<TimerMilestone>();
41+
private SortedList<float, TimerMilestone> _milestones = new SortedList<float, TimerMilestone>();
4342

4443
/// <summary>
4544
/// Initializes a new instance of the SimpleTimer class with a specified duration.
@@ -107,22 +106,24 @@ public virtual void Update(float deltaTime)
107106

108107
protected virtual void CheckAndTriggerMilestones()
109108
{
110-
_milestones.RemoveAll(milestone =>
109+
while (_milestones.Count > 0 && ShouldTrigger(_milestones.Values[0]))
111110
{
112-
var shouldTrigger = milestone.Type switch
113-
{
114-
TimeType.TimeRemaining => TimeRemaining <= milestone.TriggerValue,
115-
TimeType.TimeElapsed => TimeElapsed >= milestone.TriggerValue,
116-
TimeType.ProgressElapsed => ProgressElapsed >= milestone.TriggerValue,
117-
TimeType.ProgressRemaining => ProgressRemaining <= milestone.TriggerValue,
118-
_ => throw new ArgumentOutOfRangeException()
119-
};
120-
121-
if (!shouldTrigger) return false;
122-
111+
var milestone = _milestones.Values[0];
123112
milestone.Callback?.Invoke();
124-
return true; // Mark for removal
125-
});
113+
_milestones.RemoveAt(0);
114+
}
115+
}
116+
117+
private bool ShouldTrigger(TimerMilestone milestone)
118+
{
119+
return milestone.Type switch
120+
{
121+
TimeType.TimeRemaining => TimeRemaining <= milestone.TriggerValue,
122+
TimeType.TimeElapsed => TimeElapsed >= milestone.TriggerValue,
123+
TimeType.ProgressElapsed => ProgressElapsed >= milestone.TriggerValue,
124+
TimeType.ProgressRemaining => ProgressRemaining <= milestone.TriggerValue,
125+
_ => throw new ArgumentOutOfRangeException(nameof(milestone.Type), "Unknown TimeType")
126+
};
126127
}
127128

128129
/// <summary>
@@ -183,12 +184,12 @@ public virtual void Rewind(float seconds)
183184
/// <param name="milestone">The milestone to add to the timer.</param>
184185
public virtual void AddMilestone(TimerMilestone milestone)
185186
{
186-
_milestones.Add(milestone);
187+
_milestones.Add(milestone.TriggerValue, milestone);
187188
}
188189

189190
public virtual void RemoveMilestone(TimerMilestone milestone)
190191
{
191-
_milestones.Remove(milestone);
192+
_milestones.Remove(milestone.TriggerValue);
192193
}
193194

194195
public virtual void ClearMilestones()
@@ -198,7 +199,21 @@ public virtual void ClearMilestones()
198199

199200
public virtual void RemoveMilestonesByCondition(Predicate<TimerMilestone> condition)
200201
{
201-
_milestones.RemoveAll(condition);
202+
// Collect keys to remove to avoid modifying the collection during iteration
203+
var keysToRemove = new List<float>();
204+
foreach (var pair in _milestones)
205+
{
206+
if (condition(pair.Value))
207+
{
208+
keysToRemove.Add(pair.Key);
209+
}
210+
}
211+
212+
// Remove all identified keys
213+
foreach (var key in keysToRemove)
214+
{
215+
_milestones.Remove(key);
216+
}
202217
}
203218

204219
/// <summary>

Runtime/TimeType.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace Timers.Runtime
1+
namespace Nonatomic.Timers
22
{
33
public enum TimeType
44
{

Runtime/Timer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using System;
22
using UnityEngine;
33

4-
namespace Timers.Runtime
4+
namespace Nonatomic.Timers
55
{
66
/// <summary>
77
/// A Unity MonoBehaviour that manages a timer, allowing it to be used within the Unity Engine's update system.

Runtime/TimerMilestone.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System;
22

3-
namespace Timers.Runtime
3+
namespace Nonatomic.Timers
44
{
55
public class TimerMilestone
66
{
@@ -15,5 +15,4 @@ public TimerMilestone(TimeType type, float triggerValue, Action callback)
1515
Callback = callback;
1616
}
1717
}
18-
1918
}

Runtime/TimerUtility.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace Timers.Runtime
1+
namespace Nonatomic.Timers
22
{
33
using System;
44
using static System.TimeSpan;

Tests/EditMode/SimpleTimerTests.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using NUnit.Framework;
2-
using Timers.Runtime;
3-
using UnityEngine;
2+
using Nonatomic.Timers;
43

54
namespace Tests.EditMode
65
{
@@ -124,6 +123,22 @@ public void Rewind_And_FastForward_AreAccurate()
124123
Assert.AreEqual(4, _simpleTimer.TimeRemaining, "Operations should accurately modify TimeRemaining.");
125124
}
126125

126+
[Test]
127+
public void RemoveMilestonesByCondition_Removes_Correctly()
128+
{
129+
var triggered1 = false;
130+
var triggered2 = false;
131+
var milestone1 = new TimerMilestone(TimeType.TimeRemaining, 5, () => triggered1 = true);
132+
var milestone2 = new TimerMilestone(TimeType.TimeRemaining, 3, () => triggered2 = true);
133+
_simpleTimer.AddMilestone(milestone1);
134+
_simpleTimer.AddMilestone(milestone2);
135+
_simpleTimer.RemoveMilestonesByCondition(m => m.TriggerValue == 5);
136+
_simpleTimer.StartTimer();
137+
_simpleTimer.Update(7); // Triggers 3, not 5
138+
Assert.IsFalse(triggered1, "Removed milestone should not trigger.");
139+
Assert.IsTrue(triggered2, "Remaining milestone should trigger.");
140+
}
141+
127142
[Test]
128143
public void Milestone_Should_Trigger_When_Time_Remaining_Reaches_Specified_Value()
129144
{

0 commit comments

Comments
 (0)