// Copyright (c) 2015 - 2023 Doozy Entertainment. All Rights Reserved. // This code can only be used under the standard Unity Asset Store End User License Agreement // A Copy of the EULA APPENDIX 1 is available at http://unity3d.com/company/legal/as_terms using System; using System.Collections.Generic; using Doozy.Runtime.Common; using Doozy.Runtime.Common.Utils; using Doozy.Runtime.Mody; using Doozy.Runtime.UIManager.Content.Internal; using UnityEngine; using UnityEngine.Events; namespace Doozy.Runtime.UIManager.Content { /// /// The UIStopwatch component can be used to measure elapsed time and trigger events at specific intervals (laps). /// It works like a stopwatch, and it can be paused and resumed at any time. /// It works with both real time (unscaled time) and game time (scaled time). /// [AddComponentMenu("Doozy/UI/DateTime/UI Stopwatch")] public class UIStopwatch : DateTimeComponent { #if UNITY_EDITOR [UnityEditor.MenuItem("GameObject/Doozy/UI/DateTime/UI Stopwatch", false, 8)] private static void CreateComponent(UnityEditor.MenuCommand menuCommand) { GameObjectUtils.AddToScene("UIStopwatch", false, true); } #endif [Serializable] public struct Lap { public int lapNumber { get; private set; } public TimeSpan lapTime { get; private set; } public TimeSpan lapDuration { get; private set; } public Lap(int lapNumber, TimeSpan lapTime, TimeSpan lapDuration) { this.lapNumber = lapNumber; this.lapTime = lapTime; this.lapDuration = lapDuration; } } /// /// Current lap index (starts at 0 for the first lap) /// public int currentLapIndex { get; protected set; } /// /// Current lap number (starts at 1 for the first lap) /// public int currentLapNumber => currentLapIndex + 1; /// Keeps track of the added laps public List laps { get; protected set; } /// Callback triggered when a new lap is added public ModyEvent OnLap = new ModyEvent(); /// /// Callback triggered when a new lap is added /// This is a quick access to the OnLap ModyEvent /// public UnityEvent onLapEvent => OnLap.Event; /// Keeps track of the last time a lap was added private TimeSpan previousLapTime { get; set; } #if UNITY_EDITOR protected override void Reset() { base.Reset(); if (labels.Count == 0) labels.Add(new FormattedLabel(null, @"mm\:ss\.f")); } #endif // UNITY_EDITOR protected override void Awake() { base.Awake(); laps ??= new List(); } protected override void OnEnable() { base.OnEnable(); StartTimer(); } protected override void OnDisable() { base.OnDisable(); CancelTimer(); } protected override void UpdateCurrentTime() { base.UpdateCurrentTime(); Years = elapsedTime.Days / 365; Months = elapsedTime.Days / 30; Days = elapsedTime.Days; Hours = elapsedTime.Hours; Minutes = elapsedTime.Minutes; Seconds = elapsedTime.Seconds; Milliseconds = elapsedTime.Milliseconds; UpdateLabels(); } public override void UpdateLabels() { for (int i = 0; i < labels.Count; i++) { if (labels[i].Label == null) continue; labels[i].SetText(elapsedTime); } } public override void ResetTimer() { base.ResetTimer(); ClearLaps(); UpdateLabels(); } public override void StartTimer() { base.StartTimer(); ClearLaps(); UpdateLabels(); } public override void StopTimer() { base.StopTimer(); UpdateLabels(); } public override void PauseTimer() { base.PauseTimer(); UpdateLabels(); } public override void ResumeTimer() { base.ResumeTimer(); UpdateLabels(); } public override void FinishTimer() { StartUpdateCoroutine(); UpdateCurrentTime(); StopTimer(); OnFinish?.Execute(); UpdateLabels(); } public override void CancelTimer() { base.CancelTimer(); UpdateLabels(); } /// /// Add a new lap time and duration to the lapTimes and lapDurations dictionaries /// public void AddLap() { laps.Add ( new Lap ( currentLapNumber, //lap number elapsedTime, //lap time elapsedTime - previousLapTime //lap duration ) ); OnLap?.Execute(); //trigger the OnLap event UpdateLabels(); //update the labels currentLapIndex++; //increment the current lap index previousLapTime = elapsedTime; //update the previous lap time } /// /// Get the lap time for the given lap number (starts at 1 for the first lap) /// /// Lap number (starts at 1 for the first lap) /// Lap time for the given lap number public Lap GetLap(int lapNumber) { if (lapNumber < 1 || lapNumber > currentLapNumber) return new Lap(); return laps[lapNumber - 1]; } /// Clear the laps list and reset the current lap index public void ClearLaps() { laps.Clear(); currentLapIndex = 0; previousLapTime = TimeSpan.Zero; } protected override void SetEndTime() { endTime = startTime .AddYears(100); } } }