using System; using TriInspector; using UnityEngine; using UnityEngine.Serialization; namespace Common.Timer.Runtime { [Serializable] public class Stopwatch : Timer, IStopwatch { public override float CurrentTime { get { currentTime = Mathf.Clamp(currentTime, 0f, Duration); return currentTime; } set => currentTime = Mathf.Clamp(value, 0f, Duration); } [Title("Settings (Stopwatch)")] [SerializeField] [FormerlySerializedAs("_duration")] protected float duration; [Group("Internal"), ShowInInspector, DisableInEditMode] public virtual float Duration { get { duration = Mathf.Max(0.001f, duration); return duration; } set => duration = Mathf.Max(0.001f, value); } [SerializeField] [FormerlySerializedAs("_deactivateOnTimeReached")] protected bool deactivateOnTimeReached; public bool DeactivateOnTimeReached { get => deactivateOnTimeReached; set => deactivateOnTimeReached = value; } [Group("Internal"), ShowInInspector, DisableInEditMode] public virtual float RemainingTime { get => Mathf.Clamp(Duration - CurrentTime, 0f, Duration); set => CurrentTime = Mathf.Clamp(Duration - value, 0f, Duration); } [Group("Internal"), ShowInInspector, DisableInEditMode] public virtual float Progress { get => Duration == 0f ? 0f : Mathf.Clamp(CurrentTime / Duration, 0f, 1f); set => CurrentTime = Mathf.Clamp(Duration * value, 0f, Duration); } [Group("Internal"), ReadOnly, ShowInInspector, DisableInEditMode] public virtual bool IsTimeReached => CurrentTime >= Duration; public event Action OnTimeReached; public Stopwatch(bool isActive, float duration, bool deactivateOnTimeReached = false) : base(isActive) { this.duration = duration; this.deactivateOnTimeReached = deactivateOnTimeReached; } public override void Tick() { if (IsTimeReached) return; base.Tick(); if (!IsActive) return; if (IsTimeReached) EndTime(); } public override void SetTime(float value) { CurrentTime = value; if (IsTimeReached) EndTime(); } public virtual void SetDuration(float value) { Duration = value; if (IsTimeReached) EndTime(); } public virtual void SetRemainingTime(float value) { RemainingTime = value; if (IsTimeReached) EndTime(); } public virtual void SetProgress(float value) { Progress = value; if (IsTimeReached) EndTime(); } public virtual void EndTime() { currentTime = Duration; InvokeOnTimeReached(); if (DeactivateOnTimeReached) Deactivate(); } protected virtual void InvokeOnTimeReached() { OnTimeReached?.Invoke(); } #if UNITY_EDITOR [Group("Debug"), Button("End Time"), HideInEditMode] private void EndTimer_Editor() => EndTime(); #endif } }