내일배움캠프/Unity Final Projcet
[Unity]일일 및 주간 리셋 타이머 구현
danpat77
2025. 5. 12. 21:10
전체적인 동작 흐름
우선 전체 흐름을 간단히 살펴보면 다음과 같습니다.
→ 최초로 타이머 계산
→ 코루틴 시작
→ 매 초마다 리셋 시간이 되었는지 확인
→ 리셋 시간이 되면 이벤트 호출 및 다음 리셋 스케줄링
→ 남은 시간을 UI에 표시
ScheduleNextDailyReset()
private void ScheduleNextDailyReset()
{
DateTime now = DateTime.Now;
var todayNine = new DateTime(now.Year, now.Month, now.Day, 0, 0, 0);
nextDailyResetTime = now < todayNine ? todayNine : todayNine.AddDays(1);
}
- 역할:
- 매일 정해진 시각(여기서는 오전 0시)을 기준으로 다음 리셋 시각을 설정합니다.
- 상세 설명:
- 현재 시간이 오전 0시 전이라면 당일 0시를 다음 리셋 시간으로 설정합니다.
- 오전 0시가 지났다면 다음날 0시를 리셋 시간으로 설정합니다.
ScheduleNextWeeklyReset()
private void ScheduleNextWeeklyReset()
{
DateTime now = DateTime.Now;
int daysUntilMonday = ((int)DayOfWeek.Monday - (int)now.DayOfWeek + 7) % 7;
var targetDay = now.Date.AddDays(daysUntilMonday).AddHours(9);
nextWeeklyResetTime = now < targetDay ? targetDay : targetDay.AddDays(7);
}
- 역할:
- 매주 월요일 오전 9시를 기준으로 다음 리셋 시각을 계산하여 설정합니다.
- 상세 설명:
- 현재 요일과 시간을 기준으로 다음에 오는 월요일 오전 9시를 구합니다.
- 현재 시각이 이미 이번 주 월요일 9시를 넘었다면, 다음 주 월요일 오전 9시로 설정합니다.
CountdownCoroutine()
private IEnumerator CountdownCoroutine()
{
while (true)
{
DateTime now = DateTime.Now;
// 일일 리셋 체크
if (now >= nextDailyResetTime)
{
OnDailyReset?.Invoke();
ScheduleNextDailyReset();
}
// 주간 리셋 체크
if (now >= nextWeeklyResetTime)
{
OnWeeklyReset?.Invoke();
ScheduleNextWeeklyReset();
}
// 남은 시간 계산 및 UI 업데이트
TimeSpan remainDaily = nextDailyResetTime - now;
TimeSpan remainWeekly = nextWeeklyResetTime - now;
TimeUI(remainDaily, remainWeekly);
yield return new WaitForSeconds(1f);
}
}
- 역할:
- 1초마다 리셋 시각이 지났는지 체크합니다.
- 리셋 시각이 되었다면, 연결된 이벤트를 호출하고 다음 리셋을 설정합니다.
- UI 갱신을 위해 남은 시간을 계속해서 계산합니다.
- 상세 설명:
코루틴을 통해 지속적으로 동작하며, 매초마다 현재 시간을 점검하여 조건이 충족되면 즉시 이벤트가 호출됩니다.
TimeUI(TimeSpan, TimeSpan)
private void TimeUI(TimeSpan remainDaily, TimeSpan remainWeekly)
{
// 일일 타이머 표시 (HH시MM분SS초)
string dailyStr = string.Format("{0:D2}시{1:D2}분{2:D2}초",
(int)remainDaily.TotalHours, remainDaily.Minutes, remainDaily.Seconds);
// 주간 타이머 표시 (D일 HH시MM분 또는 HH시MM분SS초)
string weeklyStr;
if (remainWeekly.Days > 0)
{
weeklyStr = string.Format("{0}일 {1:D2}시{2:D2}분",
remainWeekly.Days, remainWeekly.Hours, remainWeekly.Minutes);
}
else
{
weeklyStr = string.Format("{0:D2}시{1:D2}분{2:D2}초",
(int)remainWeekly.TotalHours, remainWeekly.Minutes, remainWeekly.Seconds);
}
UIManager.Instance.questUIHandler.SetUITimer(dailyStr, weeklyStr);
}
- 역할:
- 화면(UI)에 표시할 남은 시간을 형식에 맞게 계산하여 UI로 넘겨줍니다.
- 상세 설명:
- 일일 타이머는 항상 시/분/초로 표현합니다.
- 주간 타이머는 1일 이상 남았으면 D일 HH시MM분 형태로 표시하고, 하루 미만이면 시간까지 초 단위로 자세하게 표시합니다.
이벤트 연결
private void OnEnable()
{
TimerManager.OnDailyReset += ResetDailyQuest;
TimerManager.OnWeeklyReset += ResetWeeklyQuest;
}
private void OnDisable()
{
TimerManager.OnDailyReset -= ResetDailyQuest;
TimerManager.OnWeeklyReset -= ResetWeeklyQuest;
}
활용법:
위처럼 다른 스크립트에서 TimerManager의 이벤트를 연결하여 사용하면 됩니다.
마무리
이번에 Unity에서 일일 및 주간 리셋 타이머 기능을 직접 만들어 보면서, 간단한 타이머 구현이라 생각했는데도 생각보다 세세한 부분에서 신경 쓸 게 많다는 걸 깨달았습니다. 특히나 날짜 계산이나 주간 기준일을 잡는 부분에서는 처음엔 약간 헷갈렸지만, 하나하나 해결해 나가면서 DateTime과 Coroutine에 대해 더 깊이 이해할 수 있었던 것 같습니다.
무엇보다도 이벤트로 처리해 놓으니 나중에 퀘스트나 다른 시스템과의 연결이 편리해진다는 점이 가장 마음에 듭니다.