
유니티에서 몇 초 뒤에 어떤 일을 하려면 IEnumerator 를 돌려주는 함수를 만들고, 그 안에서 yield return new WaitForSeconds(초) 로 기다린 뒤 StartCoroutine 으로 시작합니다. 중간에 멈추려면 StartCoroutine 이 돌려준 Coroutine 을 변수에 담아 두었다가 StopCoroutine 에 넣습니다.
IEnumerator Hide_Routine()
{
yield return new WaitForSeconds(2f); // 2초 기다림
panel_message.SetActive(false); // 그다음 줄이 실행됨
}
Coroutine routine_hide = StartCoroutine(Hide_Routine()); // 시작
StopCoroutine(routine_hide); // 멈춤
「저장했습니다」 같은 알림을 띄웠다가 2초 뒤에 닫거나, 1초마다 무언가를 되풀이할 때 Update 에서 시간을 직접 세지 않고 코루틴으로 짧게 쓸 수 있습니다. 다만 같은 버튼을 빠르게 두 번 누르면 앞에서 세던 코루틴이 그대로 남아 알림이 예상보다 일찍 닫히거나, 게임을 일시정지했더니 알림이 안 닫히는 일이 생깁니다. 이번 글에서는 알림 판을 띄우고 몇 초 뒤 닫는 DelayMessage 를 만들면서, 다시 누르면 처음부터 다시 세고 닫기 버튼으로 바로 멈추는 처리와 일시정지 중에도 시간이 흐르게 하는 선택을 함께 넣었습니다.
C# (UNITY 3D)
button_show 를 누르면 알림 판이 켜지고 show_seconds(기본 2초) 뒤에 저절로 꺼집니다. 꺼지기 전에 다시 누르면 남은 시간이 처음부터 다시 시작되고, button_hide 를 누르면 기다리지 않고 바로 꺼집니다.
1. 준비
using System.Collections;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
코루틴 함수가 돌려주는 IEnumerator 는 System.Collections 에 있습니다. 이 줄이 없으면 IEnumerator 를 찾을 수 없다는 컴파일 오류가 납니다. Button 은 UnityEngine.UI, 알림 글자 TMP_Text 는 TMPro 에 있습니다.
Canvas 아래에 알림 판(Panel)과 그 안의 TextMeshPro 글자를 만들고, 버튼 두 개를 둡니다. DelayMessage 는 알림 판이 아닌 다른 오브젝트(예: Canvas 나 빈 오브젝트)에 붙이고 인스펙터에서 판 · 글자 · 버튼을 끌어다 넣습니다. 알림 판 자신에 붙이면 판을 꺼 둔 채로 씬을 시작했을 때 Start 가 불리지 않아 버튼이 연결되지 않습니다.
2. 몇 초 뒤 닫히는 알림 코드
using System.Collections;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
//CodeFinder 코드파인더
//From https://codefinder.janndk.com/
public class DelayMessage : MonoBehaviour
{
public GameObject panel_message; // 잠깐 띄울 알림 판(이 스크립트가 붙은 오브젝트와 다른 것)
public TMP_Text text_message;
public Button button_show;
public Button button_hide;
public float show_seconds = 2f; // 몇 초 뒤에 닫을지
public bool use_realtime = false; // 켜면 Time.timeScale 이 0(일시정지)이어도 시간이 흐름
Coroutine routine_hide; // 지금 세고 있는 코루틴(멈출 때 씀)
void Start()
{
if (panel_message != null)
panel_message.SetActive(false);
if (button_show != null)
{
button_show.onClick.RemoveAllListeners();
button_show.onClick.AddListener(() => Show_Message("저장했습니다"));
}
if (button_hide != null)
{
button_hide.onClick.RemoveAllListeners();
button_hide.onClick.AddListener(Hide_Now);
}
}
public void Show_Message(string message)
{
if (text_message != null)
text_message.text = message;
if (panel_message != null)
panel_message.SetActive(true);
if (routine_hide != null)
StopCoroutine(routine_hide); // 세던 것은 멈추고 처음부터 다시 셈
routine_hide = StartCoroutine(Hide_Routine(show_seconds));
}
public void Hide_Now()
{
if (routine_hide != null)
{
StopCoroutine(routine_hide);
routine_hide = null;
}
if (panel_message != null)
panel_message.SetActive(false);
}
IEnumerator Hide_Routine(float seconds)
{
if (use_realtime)
yield return new WaitForSecondsRealtime(seconds);
else
yield return new WaitForSeconds(seconds);
if (panel_message != null)
panel_message.SetActive(false);
routine_hide = null;
}
}
StartCoroutine 은 Hide_Routine 을 첫 yield 까지만 실행하고 바로 돌아옵니다. 그래서 Show_Message 는 기다리지 않고 끝나고, 2초가 지나면 Unity 가 yield 다음 줄부터 이어서 실행해 판을 끕니다. 다시 누를 때 앞의 코루틴을 멈추지 않으면 첫 번째 것이 먼저 끝나면서 두 번째 알림까지 일찍 닫아 버리기 때문에, routine_hide 에 담아 두었다가 StopCoroutine 으로 멈춘 뒤 새로 시작합니다.
WaitForSeconds 는 Time.timeScale 의 영향을 받는 시간(scaled time)으로 셉니다. 일시정지 화면에서 timeScale 을 0 으로 두면 이 시간은 흐르지 않아 알림이 닫히지 않습니다. use_realtime 을 켜면 WaitForSecondsRealtime 으로 바뀌어 실제 시간으로 셉니다.
이 스크립트는 Unity 6000.6.3f1 에서 컴파일 오류 없이 들어갔고, 배치 모드에서 Start 를 불러도 예외가 없었습니다. 배치 모드는 플레이 루프가 돌지 않아 2초가 실제로 흐르는 것은 보지 못했고, 코루틴을 한 칸씩 직접 넘기며 단계마다 값을 확인했습니다(3절).
변수(variable)
panel_message(GameObject) : 잠깐 띄울 알림 판
text_message(TMP_Text) : 알림 글자
button_show(Button) : 알림 띄우기 버튼
button_hide(Button) : 바로 닫기 버튼
show_seconds(float) : 몇 초 뒤에 닫을지
use_realtime(bool) : 일시정지 중에도 시간을 셀지
routine_hide(Coroutine) : 지금 세고 있는 코루틴
함수(function)
Start : 알림 판을 끄고 두 버튼에 Show_Message · Hide_Now 를 연결합니다.
Show_Message : 글자를 바꾸고 판을 켠 뒤, 세던 코루틴이 있으면 멈추고 Hide_Routine 을 새로 시작합니다.
Hide_Now : 세던 코루틴을 멈추고 판을 바로 끕니다.
Hide_Routine : 정한 초만큼 기다린 뒤 판을 끕니다.
3. 한 칸씩 넘겨 본 값

Show_Message 를 부르면 판이 켜지고 routine_hide 에 Coroutine 이 들어갔습니다. 한 번 더 부르면 앞과 다른 새 Coroutine 이 들어가고, Hide_Now 를 부르면 판이 꺼지고 routine_hide 가 비었습니다. Hide_Routine 을 한 칸 넘기면 WaitForSeconds 에서 멈춘 채 판은 켜져 있고, 한 칸 더 넘기면 판이 꺼지면서 코루틴이 끝났습니다. use_realtime 을 켜면 첫 칸이 WaitForSecondsRealtime(2) 로 바뀌었습니다.
4. 되풀이 · 한 프레임 · 조건 기다리기
IEnumerator Repeat_Routine(float interval)
{
var wait = new WaitForSeconds(interval); // 같은 간격이면 하나 만들어 두고 다시 씀
while (true)
{
count_tick++;
yield return wait;
}
}
IEnumerator Next_Frame()
{
yield return null; // 다음 프레임
yield return new WaitForEndOfFrame(); // 이번 프레임 그리기가 끝난 뒤
}
IEnumerator Wait_Tick(int target)
{
yield return new WaitUntil(() => count_tick >= target); // 조건이 참이 될 때까지
Debug.Log("tick " + target);
}
StopAllCoroutines(); // 이 스크립트가 돌린 코루틴을 모두 멈춤
while(true) 안에서 기다리면 멈출 때까지 일정 간격으로 되풀이됩니다. 간격이 늘 같다면 WaitForSeconds 를 밖에서 한 번만 만들어 두고 다시 써도 되고, 세 번 넘겨 보니 매번 같은 개체가 돌아왔습니다. yield return null 은 한 프레임만 쉬고, WaitUntil 은 조건이 참이 될 때까지 매 프레임 확인합니다(count_tick 이 3 일 때는 계속 기다리고, 5 가 되자 기다림이 풀렸습니다). StopAllCoroutines 는 이 스크립트가 시작한 코루틴만 멈추고, 다른 스크립트의 코루틴은 건드리지 않습니다.
5. 안 될 때 — 자주 하는 실수
꺼진 오브젝트에서 시작했다
스크립트가 붙은 오브젝트가 꺼져 있으면 코루틴이 시작되지 않습니다. 확인해 보니 예외 없이 Console 에 「Coroutine couldn't be started because the the game object 'Messenger' is inactive!」 오류만 남고 routine_hide 는 비어 있었습니다. 판은 이미 켜졌는데 닫는 코루틴이 없으니 알림이 계속 떠 있게 됩니다. 켜고 끄는 판은 따로 두고, 스크립트가 붙은 오브젝트는 늘 켜 두어야 하는 이유입니다.
도중에 오브젝트를 껐더니 코루틴이 사라졌다
Unity 문서에 따르면 스크립트가 붙은 오브젝트의 activeSelf 가 false 가 되거나 스크립트가 Destroy 되면 코루틴도 멈춥니다. 다시 켜도 이어지지 않으니 필요하면 다시 시작해야 합니다. 반대로 스크립트의 enabled 만 false 로 바꾸는 것으로는 멈추지 않습니다.
StopCoroutine 을 불렀는데 안 멈춘다
StopCoroutine 에는 시작할 때 쓴 바로 그 값(같은 IEnumerator 변수나 StartCoroutine 이 돌려준 Coroutine)을 넣어야 합니다. StartCoroutine(Hide_Routine(2f)) 로 시작해 놓고 StopCoroutine(Hide_Routine(2f)) 를 부르면 새로 만든 다른 IEnumerator 를 넘기는 것이라 처음 것은 멈추지 않습니다. 이 글처럼 StartCoroutine 이 돌려준 Coroutine 을 담아 두었다가 넘기는 것이 가장 헷갈리지 않습니다.
일시정지하면 안 끝난다
Time.timeScale = 0 이면 WaitForSeconds 는 흐르지 않습니다. 일시정지 메뉴의 알림처럼 멈춘 동안에도 닫혀야 하는 것은 WaitForSecondsRealtime 을 씁니다.
함께 보기: Update 에서 시간을 직접 세는 카운트다운 · 스톱워치는 유니티 타이머 카운트다운 · 스톱워치 · 일시정지 (Time.deltaTime, unscaledDeltaTime), 버튼에 함수를 코드로 다는 법은 유니티 Button onClick 코드로 연결 · interactable 로 잠금 · 연타 막기 (AddListener, 반복문 람다) 에 있습니다.
코루틴 동작은 Unity 공식 문서 Coroutines · MonoBehaviour.StartCoroutine · MonoBehaviour.StopCoroutine · WaitForSeconds 와 Unity 6000.6.3f1 에디터(Windows)에서 값을 넣어 본 결과를 기준으로 적었습니다.
'Unity3D > C#' 카테고리의 다른 글
| 유니티 씬 전환 · 로딩 바 (SceneManager.LoadScene, LoadSceneAsync) (0) | 2026.11.02 |
|---|---|
| 유니티 노치 화면 대응 · 안전 영역 (Screen.safeArea) (0) | 2026.10.31 |
| 유니티 안드로이드 뒤로가기 · 앱 종료 (KeyCode.Escape) (0) | 2026.10.30 |
| 유니티 앱 내릴 때 자동 저장 (OnApplicationPause) (0) | 2026.10.29 |
| 유니티 진동 울리기 · 진동 끄기 설정 (Handheld.Vibrate) (0) | 2026.10.28 |