설명은 주석으로 대체
using System;
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections.Generic;
/// <summary>
/// Unity 6의 Awaitable을 활용하여 비동기 타이머 기능을 제공하는 클래스입니다.
/// </summary>
public class AwaitableTimer
{
private static Dictionary<int, TimerInfo> activeTimers = new Dictionary<int, TimerInfo>();
private static int timerId;
private static bool isInitialized;
public static event Action OnTimerStarted;
private class TimerInfo
{
public float StartTime { get; set; }
public float Duration { get; set; }
public Action OnComplete { get; set; }
public Action<float> OnUpdate { get; set; }
public bool IsPaused { get; set; }
public float ElapsedTime { get; set; }
}
/// <summary>
/// 현재 실행 중인 타이머가 있는지 확인합니다.
/// </summary>
public static bool HasActiveTimers => activeTimers.Count > 0;
static AwaitableTimer()
{
InitializeIfNeeded();
}
private static void InitializeIfNeeded()
{
if (!isInitialized)
{
SceneManager.sceneUnloaded += OnSceneUnloaded;
Application.quitting += CleanupAllTimers;
isInitialized = true;
}
}
private static void OnSceneUnloaded(Scene scene)
{
CleanupAllTimers();
}
/// <summary>
/// 모든 타이머를 정리하고 메모리를 해제합니다.
/// </summary>
public static void CleanupAllTimers()
{
activeTimers.Clear();
timerId = 0;
}
/// <summary>
/// 타이머를 시작하고 설정된 시간 후에 콜백을 호출합니다.
/// </summary>
/// <param name="time">타이머 지속 시간</param>
/// <param name="onComplete">타이머 완료 시 호출할 콜백</param>
/// <param name="onUpdate">타이머 업데이트 시 호출할 콜백</param>
/// <returns>타이머 ID</returns>
public static int StartTimer(float time, Action onComplete, Action<float> onUpdate = null)
{
if (time <= 0)
{
onComplete?.Invoke();
return -1;
}
InitializeIfNeeded();
OnTimerStarted?.Invoke();
timerId++;
int currentTimerId = timerId;
var timerInfo = new TimerInfo
{
StartTime = Time.time,
Duration = time,
OnComplete = onComplete,
OnUpdate = onUpdate,
IsPaused = false,
ElapsedTime = 0f
};
activeTimers[currentTimerId] = timerInfo;
RunTimerAsync(currentTimerId);
return currentTimerId;
}
private static async void RunTimerAsync(int id)
{
if (activeTimers.TryGetValue(id, out TimerInfo timerInfo))
{
while (timerInfo.ElapsedTime < timerInfo.Duration)
{
if (timerInfo.IsPaused)
{
await Awaitable.NextFrameAsync();
continue;
}
timerInfo.ElapsedTime += Time.deltaTime;
timerInfo.OnUpdate?.Invoke(timerInfo.ElapsedTime);
await Awaitable.NextFrameAsync();
}
timerInfo.OnComplete?.Invoke();
activeTimers.Remove(id);
}
}
/// <summary>
/// 특정 ID의 타이머를 중지합니다.
/// </summary>
public static void StopTimer(int id)
{
if (activeTimers.ContainsKey(id))
{
activeTimers.Remove(id);
}
}
/// <summary>
/// 특정 ID의 타이머를 일시정지합니다.
/// </summary>
public static void PauseTimer(int id)
{
if (activeTimers.TryGetValue(id, out TimerInfo timerInfo))
{
timerInfo.IsPaused = true;
}
}
/// <summary>
/// 특정 ID의 타이머를 재개합니다.
/// </summary>
public static void ResumeTimer(int id)
{
if (activeTimers.TryGetValue(id, out TimerInfo timerInfo))
{
timerInfo.IsPaused = false;
}
}
/// <summary>
/// 특정 ID의 타이머가 실행 중인지 확인합니다.
/// </summary>
public static bool IsTimerRunning(int id)
{
return activeTimers.ContainsKey(id) && !activeTimers[id].IsPaused;
}
/// <summary>
/// 특정 ID의 타이머의 남은 시간을 반환합니다.
/// </summary>
public static float GetRemainingTime(int id)
{
if (activeTimers.TryGetValue(id, out TimerInfo timerInfo))
{
return timerInfo.Duration - timerInfo.ElapsedTime;
}
return 0f;
}
}