using System; using UnityEngine; namespace SK.Framework { /// /// 倒计时/定时器 /// public sealed class Countdown : ITimer { private float beginTime; private readonly float duration; private float pausedTime; private readonly bool isIgnoreTimeScale; private readonly MonoBehaviour executer; private Action onLaunch; private Action onExecute; private Action onPause; private Action onResume; private Action onStop; private Func stopWhen; /// /// 剩余计时时长 /// public float RemainingTime { get; private set; } public bool IsCompleted { get; private set; } public bool IsPaused { get; private set; } public Countdown(float duration, bool isIgnoreTimeScale = false, MonoBehaviour executer = null) { this.duration = duration; this.isIgnoreTimeScale = isIgnoreTimeScale; this.executer = executer; } public Countdown OnLaunch(Action onLaunch) { this.onLaunch = onLaunch; return this; } public Countdown OnExecute(Action onExecute) { this.onExecute = onExecute; return this; } public Countdown OnPause(Action onPause) { this.onPause = onPause; return this; } public Countdown OnResume(Action onResume) { this.onResume = onResume; return this; } public Countdown OnStop(Action onStop) { this.onStop = onStop; return this; } public Countdown StopWhen(Func predicate) { stopWhen = predicate; return this; } public void Launch() { beginTime = isIgnoreTimeScale ? Time.realtimeSinceStartup : Time.time; onLaunch?.Invoke(); this.Begin(executer != null ? executer : Timer.Instance); } public void Pause() { IsPaused = true; pausedTime = isIgnoreTimeScale ? Time.realtimeSinceStartup : Time.time; onPause?.Invoke(); } public void Resume() { IsPaused = false; beginTime += (isIgnoreTimeScale ? Time.realtimeSinceStartup : Time.time) - pausedTime; onResume?.Invoke(); } public void Stop() { IsCompleted = true; } public bool Execute() { if (!IsCompleted && !IsPaused) { RemainingTime = duration - ((isIgnoreTimeScale ? Time.realtimeSinceStartup : Time.time) - beginTime); RemainingTime = Mathf.Clamp(RemainingTime, 0f, duration); onExecute?.Invoke(RemainingTime); } IsCompleted = RemainingTime <= 0; if (!IsCompleted && stopWhen != null && stopWhen.Invoke()) { IsCompleted = true; } if (IsCompleted) { onStop?.Invoke(); } return IsCompleted; } } }