Quick Reference
Timeline 1.8.12 기준입니다. Track은 "언제 무엇을 제어할지"를 역할별로 나누는 시간 축이고, Signal은 그 시간 축에서 코드로 넘기는 경계입니다. 기본 Signal Track에서는 SignalAsset을 SignalEmitter marker가 보내고, binding된 SignalReceiver가 UnityEvent로 받습니다.
| Track | 맡길 일 | 상태 소유 경계 |
|---|---|---|
| Animation | Animator·Animation Clip의 포즈와 움직임 | 영구 스탯·전투 판정은 코드 |
| Audio | 대사·효과음·BGM의 재생 구간 | 오디오 자산·mixer routing은 별도 시스템 |
| Activation | GameObject 활성/비활성 시간 | 생성·파괴·pool 반환 책임은 코드 |
| Cinemachine | 컷신 Camera와 blend의 시간 배치 | 평상시 priority/target 제어는 카메라 시스템 |
| Control | 다른 PlayableDirector, Particle System 등 하위 재생 제어 | 부모·자식의 시작·중지 소유자를 명시 |
| Signal | 특정 시점의 코드 알림 | 저장·보상·퀘스트 같은 영속 상태는 수신 코드 |
SignalAsset "BossIntroFinished"
-> SignalEmitter marker (Signal Track의 12.0초)
-> Signal Track이 binding된 SignalReceiver로 notification 전송
-> SignalReceiver reaction의 UnityEvent
-> 게임 규칙 코드가 idempotent하게 상태 변경Track을 나누는 기준
한 Track에는 한 가지 제어 책임을 둡니다. 캐릭터의 모션, Camera, 오디오, 게임 로직 호출을 Animation Track 하나에 억지로 묶으면 clip 이동 하나가 서로 다른 의도를 동시에 바꿉니다. Group Track은 관련 Track을 보기 좋게 묶는 용도이지 binding·재생 책임을 합치는 기능이 아닙니다.
Activation Track은 "해당 시점에 GameObject가 active인가"를 표현할 때 적합합니다. 하지만 pool에서 꺼내고 되돌리기, listener 등록 해제, 씬 전환 후 참조 정리는 Activation Track에 숨기지 않습니다. 어떤 시스템이 만든 오브젝트인지와 어떤 조건에서 반환할지는 코드가 소유합니다.
Control Track으로 sub-timeline이나 particle을 재생할 때는 중첩된 Director의 wrap·재생 시점을 부모의 Timeline과 맞춥니다. 자식 Director가 독자적으로 Play On Awake도 켜져 있으면, 부모가 아직 제어하기 전부터 재생되어 두 timeline이 같은 대상을 동시에 다룰 수 있습니다.
Signal 설정과 수신
- Project 창에서
SignalAsset을 만들고, 의미가 드러나는 이름을 붙입니다. - Timeline의
Signal Track에SignalEmittermarker를 두고Asset에 그 SignalAsset을 지정합니다. - 수신 GameObject에
SignalReceiver를 붙이고, Director의Bindings에서 그 Signal Track을 이 SignalReceiver에 연결합니다. Signal Track은 SignalReceiver를 binding 대상으로 사용합니다. - SignalReceiver의 reaction 목록에서 같은 SignalAsset을 등록하고 UnityEvent를 연결합니다. UnityEvent는 별도 MonoBehaviour의 public 메서드에 연결합니다.
SignalEmitter의 Emit Once는 Timeline이 loop될 때 그 signal을 한 번만 보낼지 정합니다. 반복 BGM cue처럼 loop마다 보내야 하는 signal에는 끄지만, 보상 지급·컷신 종료처럼 한 번만 발생해야 하는 이벤트에는 켜는 편이 안전합니다. Retroactive는 재생이 marker 시점 뒤에서 시작될 때도 signal을 보낼지 결정합니다. checkpoint에서 중간 재생할 때 필요한 초기화에는 쓸 수 있지만, 이미 끝난 퀘스트를 다시 완료시키는 신호에는 위험합니다.
using UnityEngine;
public sealed class CutsceneSignalHandler : MonoBehaviour
{
[SerializeField] private QuestState questState;
// SignalReceiver reaction의 UnityEvent에서 이 메서드를 지정합니다.
public void CompleteIntro()
{
if (!questState.IntroCompleted)
{
questState.CompleteIntro();
}
}
}SignalReceiver는 내부적으로 INotificationReceiver.OnNotify(Playable, INotification, object) 계약을 구현해 reaction을 실행합니다. 기본 Signal Track의 Inspector binding 타입은 SignalReceiver이므로, 일반 프로젝트에서는 UnityEvent를 public 메서드에 연결하는 경로가 가장 직접적입니다. 별도의 INotificationReceiver 구현체를 만들어 Signal Track의 대체 binding으로 넣을 수 있다고 가정하지 않습니다. custom notification을 직접 처리하려면 그 수신 타입을 지원하는 custom Track/Playable output까지 함께 설계합니다.
재생, seek, 반복에서의 안전성
Signal은 Timeline이 marker를 통과할 때 발생합니다. 따라서 Loop, replay, start time 변경, seek 뒤 Evaluate() 같은 재생 방식에 따라 같은 시점이 다시 평가될 수 있습니다. Timeline이 "한 번만 일어나야 하는 게임 규칙"을 보장한다고 가정하지 않습니다.
| 상황 | Signal 설정·코드에서 확인할 점 | 방치했을 때 |
|---|---|---|
| 컷신을 다시 재생 | Emit Once 의미와 게임 상태의 중복 처리 방지 | 보상·퀘스트가 여러 번 지급 |
| 중간 checkpoint에서 시작 | Retroactive 필요 여부와 시작 시 준비해야 할 상태 | 앞부분 신호가 누락되거나 과거 상태가 재실행 |
Wrap Mode: Loop | 반복해도 안전한 signal만 loop 안에 둠 | UI 생성·listener 등록·VFX가 중첩 |
time 변경 후 Evaluate() | 평가가 상태·notification에 미칠 효과를 테스트 | scrub/replay에서 예상 밖 이벤트 |
| 씬 unload 또는 binding 교체 | Receiver와 Director의 생명주기를 같이 정리 | Missing Reference, 수신하지 않는 signal |
컷신을 보는 동안의 입력 잠금, HUD 숨김처럼 재생 동안 유지되는 상태는 시작과 종료를 대칭으로 처리합니다. Signal 하나로 시작만 하고 종료 signal이 누락되면, 중간 skip이나 씬 전환에서 입력이 영구히 잠긴 상태가 되기 쉽습니다. skip 경로는 Stop()만 호출하는 대신, 게임 상태·UI·Camera를 복구하는 단일 정리 함수를 호출하도록 설계합니다.
자주 틀리는 부분
| 증상 | 원인 | 수정 |
|---|---|---|
| Signal marker가 있는데 UnityEvent가 안 불림 | Emitter의 Asset과 Receiver reaction의 SignalAsset이 다르거나 Receiver가 없음 | 동일 asset 참조와 Director/Receiver가 살아 있는지 확인 |
| 컷신 재생마다 퀘스트가 중복 진행 | Signal을 한 번성 게임 규칙으로 직접 사용 | Emit Once와 코드의 완료 여부 검사를 함께 적용 |
| sub-timeline이 먼저 또는 두 번 재생 | 부모 Control Track과 자식 Play On Awake가 동시에 소유 | 재생 소유자를 하나로 정하고 다른 자동 시작을 끔 |
| Activation만으로 pool 객체를 관리 | inactive가 반환·reset·listener 정리를 의미한다고 가정 | pool owner가 lifecycle을 처리하고 Timeline은 표시 시간만 제어 |
| skip 뒤 HUD·입력·Camera가 복구되지 않음 | 종료 signal에만 정리 로직을 둠 | 정상 종료·skip·scene unload가 공유하는 cleanup 경로를 만듦 |
참고 링크
3 sources