[Unity] 코루틴과 Animator의 시간 충돌

shin0112·2025년 10월 29일

Unity

목록 보기
6/13

✨ 들어가며

드론이 충돌하면 damage 애니메이션이 실행되고, 일정 시간이 지난 뒤 die 애니메이션으로 전환되길 원했다.

public void Die()
{
    _animator.SetBool(IsDamage, true);
    StartCoroutine(TransitionToDead(1f)); // 1초 뒤 사망
}

private IEnumerator TransitionToDead(float delay)
{
    yield return new WaitForSeconds(delay);

    _animator.SetBool(IsDamage, false);
    _animator.SetBool(IsDead, true);

    Debug.Log("드론 파괴");
}

이 코루틴의 동작 순서는 다음과 같다.

  1. damage 애니메이션을 실행한다.
  2. 1초 동안 기다린다. (damage 애니메이션 길이 기준)
  3. IsDamage = false, IsDead = true로 바꾸며 die 애니메이션으로 전환한다.

이 로직으로 드론이 충돌 후 정상적으로 파괴되고, 재시작하면 다시 idle 상태로 돌아가는 걸 확인했다.

하지만 문제가 있었다. (배경도 문제가 많은데 이것도 해결해야 한다...)

충돌 후 대미지 애니메이션이 끝나기도 전에 재시작 버튼을 누르면, 드론이 idle로 돌아오지 않고 파괴된 상태가 그대로 유지되는 문제가 발생했다.

1️⃣ 원인 찾기

애니메이터 구성은 아래와 같았다.

  • IsDamage = true | Idle → Damage
  • IsDead = true | Damage → Die
  • IsDead = false | Die → Idle

처음에는 상태를 전환하는 부분이 코루틴이라, “코루틴을 멈추면 되겠지?” 싶어서 DroneControllerResetState()에서 모든 코루틴을 종료시켰다.

public void ResetState()
{
    _isDead = false;
    if (_animator != null)
    {
        StopAllCoroutines();
        Debug.Log("모든 코루틴 종료");
        _animator.Idle();
    }
}

하지만 여전히 드론은 파괴된 상태로 유지됐다.
알고 보니 StopAllCoroutines()은 같은 스크립트 안에서만 동작한다는 사실을 알게 됐다.

그래서 아예 DroneHandlerIdle()에서 코루틴을 멈추도록 수정했다.

public override void Idle()
{
    StopAllCoroutines();
    Debug.Log("모든 코루틴 종료");

    _animator.SetBool(IsDamage, false);
    _animator.SetBool(IsDead, false);
}

그런데도 damage 애니메이션 상태가 계속 반복되는 문제가 생겼다.
로그를 찍어보면 IsDamage, IsDead가 모두 false인데도 애니메이션은 Damage 상태였다.

2️⃣ 전이선 문제

문제는 전이선(Transition Line) 이었다.

Damage → Idle로 가는 전이선이 없었던 것.
즉, Damage에서 빠져나갈 길이 없어서 계속 같은 상태에 머물고 있었던 것이다.

상태전이 조건
Idle → DamageIsDamage = true
Damage → DieIsDead = true
Die → IdleIsDead = false
Damage → IdleIsDamage = false (추가 필요)

이 전이선을 추가해주니 문제없이 해결됐다.

3️⃣ 코루틴과 상태 덮어쓰기

전이선을 추가하더라도, 코루틴을 멈추지 않고 Idle()로 전환하면 다음과 같은 실행 흐름으로, 충돌하더라도 원하는 애니메이션(대미지 받고 부서지기)이 나오지 않는다.

Die() 
→ IsDamage = true
→ 코루틴 들어감
→ 중간에 Idle() 수행
→ IsDamage = false, IsDead = false
→ 하지만 코루틴은 아직 실행 중
→ 코루틴이 다시 IsDead = true로 덮어씀
→ Idle에서 Damage로 들어갈 때, 남아있는 IsDead로 인해 Die 상태로 전환됨

코루틴이 멈추지 않으면 비동기적으로 Animator 상태를 다시 덮어쓰기 때문에, Idle로 돌아간 직후에도 갑자기 다시 Die 애니메이션이 실행되는 현상이 생긴다.

Animator와 코루틴이 서로 다른 타이밍에 같은 데이터를 제어하기 때문에 발생하는 논리 충돌이다.

Unity의 코루틴은 yield return을 만나면 일시 정지했다가, 정해진 시간이 지나면 현재 객체의 생명주기와 상관없이 다시 재개된다.
그 오브젝트가 Idle 상태로 전환되더라도 코루틴이 살아 있다면 내부 코드가 Animator 파라미터를 다시 변경해 버린다.


✍️ 마치며

결국 이런 문제는 코루틴과 Animator가 실행 순서대로 흘러가지 않는다(비동기)는 걸 충분히 인식하지 못했을 때 생긴다.

즉, “논리적으로는 이미 초기화된 상태”라도 비동기로 남은 코루틴이 과거의 신호를 다시 던지면, 결국 현재 상태가 과거에 덮어씌워지는 상황이 된다.

이런 비동기 구조에서는 하나의 상태를 여러 시스템이 동시에 제어하지 않도록 설계하는 게 중요하다.
그리고 꼭 코루틴을 써야 한다면, 그 코루틴이 언제, 어떤 조건에서 완전히 끝나는지를 항상 의식해야 한다.

결국 문제의 핵심은 두 가지였다.

  1. 코루틴을 정확히 중단하지 않으면 이전 상태가 남는다.
  2. 애니메이션 전이선을 제대로 연결하지 않으면 Animator가 상태를 잃는다.

🎯 한 줄 요약
코루틴과 애니메이터는 “동시에 상태를 관리하는 시스템”이다.
하나라도 놓치면 애니메이션이 꼬인다.
전이선 구조와 코루틴의 종료 타이밍을 항상 염두에 두자.

0개의 댓글