diff --git a/Assets/_DDD/_Scripts/GameFramework/TimeManager.cs b/Assets/_DDD/_Scripts/GameFramework/TimeManager.cs new file mode 100644 index 000000000..536e4bcb0 --- /dev/null +++ b/Assets/_DDD/_Scripts/GameFramework/TimeManager.cs @@ -0,0 +1,85 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using UnityEngine; + +namespace DDD +{ + public class TimeManager : Singleton, IManager, IEventHandler + { + private readonly Dictionary _timeScaleRequests = new(); + public float CurrentTimeScale { get; private set; } = 1f; + + private float _baseFixedDeltaTime; + + public void PreInit() + { + _baseFixedDeltaTime = Time.fixedDeltaTime; + EventBus.Register(this); + } + + public Task Init() + { + return Task.CompletedTask; + } + + public void PostInit() + { + + } + + private void OnDestroy() + { + EventBus.Unregister(this); +#if UNITY_EDITOR + Time.fixedDeltaTime = _baseFixedDeltaTime; // 재실행 시 값 복원 (Editor용 안전장치) +#endif + } + + protected override void OnApplicationQuit() + { + base.OnApplicationQuit(); + + Time.fixedDeltaTime = _baseFixedDeltaTime; + } + + private void UpdateTimeScale() + { + // 우선순위: 0이 하나라도 있으면 무조건 정지, 그 외엔 최소값 적용 + float newTimeScale = 1f; + + if (_timeScaleRequests.ContainsValue(0f)) + { + newTimeScale = 0f; + } + else if (_timeScaleRequests.Count > 0) + { + newTimeScale = Mathf.Min(1f, Mathf.Min(float.MaxValue, GetMinTimeScale())); + } + + if (Mathf.Approximately(newTimeScale, CurrentTimeScale)) return; + + CurrentTimeScale = newTimeScale; + Time.timeScale = CurrentTimeScale; + Time.fixedDeltaTime = _baseFixedDeltaTime * CurrentTimeScale; + } + + private float GetMinTimeScale() => _timeScaleRequests.Values.Prepend(1f).Min(); + + public bool IsPaused => Mathf.Approximately(CurrentTimeScale, 0f); + + public void Invoke(TimeScaleChangeEvent evt) + { + if (evt.NewTimeScale < 1f) + { + _timeScaleRequests[evt.Requester] = evt.NewTimeScale; + } + else + { + _timeScaleRequests.Remove(evt.Requester); + } + + UpdateTimeScale(); + } + } +} \ No newline at end of file