트윈
Time 서비스의 클럭으로 구동되는, 31개 이징 커브를 갖춘 일시정지 인식 값 애니메이션.
어떤 값이든 시간에 걸쳐 A에서 B로 애니메이션하세요 — 일시정지 메뉴 대응은 공짜입니다.
| 인터페이스 | ITweenService |
| 끄기 스위치 | NullTweenService |
| 어셈블리 | CommonGameSystem.Core |
| 시작 | 부팅 시 자동 등록 — 별도 설정 불필요 |
주요 기능
트윈은 시작 값과 끝 값 사이를 정해진 시간 동안 부드럽게 보간하는 것입니다. Tween 서비스가 매 틱 그 값을 계산하고, 이징 커브가 가속의 형태를 결정합니다(느리게 시작해 빨라지기, 오버슈트 후 안착, 바운스 등). 각 값을 오브젝트에 적용하는 콜백은 여러분이 제공합니다 — 프레임워크는 계산만 합니다. 리플렉션도, 자동 프로퍼티 쓰기도, 외부 의존성도 없습니다.
모든 트윈은 Time 서비스의 클럭 — Gameplay, UI, Background — 중 하나에 바인딩되므로, 추가 코드 없이 애니메이션이 일시정지 메뉴와 슬로 모션을 존중합니다. Gameplay 클럭 위의 문 열림 트윈은 플레이어가 일시정지하면 멈추고, UI 클럭 위의 메뉴 페이드는 계속 돕니다.
빠른 시작
Awake나 Start에서 서비스를 한 번 리졸브하고 캐시하세요:
using CommonGameSystem.Core;
using UnityEngine;
[DefaultExecutionOrder(100)] // Run after the framework has started.
public class MyMovingThing : MonoBehaviour
{
private ITweenService _tween;
private void Awake()
{
_tween = ServiceLocator.Resolve<ITweenService>();
}
private void StartMove()
{
_tween.To(
from: transform.position,
to: new Vector3(5f, 0f, 0f),
durationSeconds: 0.5f,
onUpdate: pos => transform.position = pos,
ease: EaseType.OutQuad
);
}
}
API 레퍼런스
타입별 To / From 오버로드 표면
서비스는 정확히 여섯 가지 값 타입을 지원하며, 각 타입마다 전용 타입 오버로드 세트가 있습니다:
float · Vector2 · Vector3 · Vector4 · Color · Quaternion
각 타입에는 네 개의 오버로드 — To 또는 From, 기본 클럭 또는 명시적 Clock 파라미터 — 가 있어 총 24개 메서드입니다. 모두 같은 형태를 공유합니다(여기서는 float 기준이며, 여섯 타입 중 무엇이든 대입하면 됩니다):
IDisposable To(float from, float to, float durationSeconds,
Action<float> onUpdate,
EaseType? ease = null,
Func<float, float> customEase = null,
Action onComplete = null);
IDisposable To(float from, float to, float durationSeconds, Clock clock,
Action<float> onUpdate,
EaseType? ease = null,
Func<float, float> customEase = null,
Action onComplete = null);
IDisposable From(float from, float current, float durationSeconds,
Action<float> onUpdate,
EaseType? ease = null,
Func<float, float> customEase = null,
Action onComplete = null);
IDisposable From(float from, float current, float durationSeconds, Clock clock,
Action<float> onUpdate,
EaseType? ease = null,
Func<float, float> customEase = null,
Action onComplete = null);
From(a, current, ...)는 To(a, current, ...)와 같은 연산입니다 — 어떤 값에서 현재 값으로 되돌아가게 애니메이션할 때(예: 펀치 인 스케일 효과) 이름이 더 잘 읽힐 뿐입니다.
의도적으로 제네릭 To<T> 메서드는 없습니다: 고정된 타입 오버로드 세트는 Unity의 AOT(IL2CPP) 컴파일에서 확실히 동작하는 반면, 값 타입에 대한 열린 제네릭 메서드는 런타임에 실패할 수 있습니다. Quaternion 트윈은 Quaternion.Slerp를 사용해 최단 호를 따라 회전합니다.
To와 From 모두 IDisposable 토큰을 반환합니다 — 트윈을 조기에 취소하려면 dispose하세요.
파라미터
from,to(또는current) — 시작 값과 끝 값.durationSeconds— 애니메이션 길이(초). 0이면 즉시to값으로 완료됩니다.clock— 선택.Clock.Gameplay(기본값)는 게임과 함께 일시정지되고,Clock.UI는 일시정지 메뉴 중에도 계속 돌며,Clock.Background는 항상 돕니다.onUpdate— 매 틱 보간된 값과 함께 호출됩니다. 오브젝트에 적용하는 것은 여러분의 몫입니다.ease— 선택적EaseType. 생략하면 기본 이징을 쓰고, 원하면 아래 31개 커브 중 하나를 고르세요.customEase— 진행도(0~1)를 이징된 진행도로 매핑하는 선택적Func<float, float>. 제공하면ease를 덮어씁니다.onComplete— 트윈이 100%에 도달할 때 한 번 발화합니다. 취소 시에는 발화하지 않습니다.
31개 이징 커브
EaseType은 Linear에 더해 열 개의 커브 패밀리를 각각 세 방향 — In(가속하며 진입), Out(감속하며 이탈), InOut(둘 다) — 으로 제공합니다:
| 패밀리 | 멤버 | 특성 |
|---|---|---|
| Linear | Linear | 일정한 속도, 이징 없음 |
| Quad | InQuad · OutQuad · InOutQuad | 완만한 가속(제곱) |
| Cubic | InCubic · OutCubic · InOutCubic | 중간 가속(세제곱) |
| Quart | InQuart · OutQuart · InOutQuart | 강한 가속 |
| Quint | InQuint · OutQuint · InOutQuint | 매우 강한 가속 |
| Sine | InSine · OutSine · InOutSine | 부드러운 파동 기반 이징 |
| Expo | InExpo · OutExpo · InOutExpo | 극적인 지수 램프 |
| Circ | InCirc · OutCirc · InOutCirc | 원호, 한쪽 끝이 급격함 |
| Back | InBack · OutBack · InOutBack | 목표를 지나쳤다가 안착 |
| Elastic | InElastic · OutElastic · InOutElastic | 목표를 스프링처럼 지나쳐 진동 |
| Bounce | InBounce · OutBounce · InOutBounce | 경계에서 공처럼 튕김 |
경험칙: 대부분의 UI 모션에는 OutQuad나 OutCubic, 경쾌한 팝인에는 OutBack, 카툰풍 강조에는 OutBounce와 Elastic 계열을 쓰세요.
진단
int ActiveCount { get; }— 살아 있는 트윈의 개수. 진단 전용이며 메인 스레드 전용입니다.
예제
패널을 0.3초 동안 페이드 인하고 완료 시 로그 남기기:
CanvasGroup panel = GetComponent<CanvasGroup>();
_tween.To(
from: 0f,
to: 1f,
durationSeconds: 0.3f,
clock: Clock.UI, // UI clock: keep running while the pause menu is open.
onUpdate: alpha => panel.alpha = alpha,
ease: EaseType.OutCubic,
onComplete: () => Debug.Log("Fade complete!")
);
토큰을 dispose해 트윈 취소하기:
float score = 0f;
IDisposable token = _tween.To(0f, 100f, 1f, v => score = v);
// ... later, if you want to stop early:
token.Dispose(); // The tween cancels; onComplete does NOT fire.
끄기
ServiceLocator.Replace<ITweenService>(new NullTweenService());
모든 트윈이 무음이 됩니다. To와 From은 공유되는 빈 토큰을 반환하고, 어떤 콜백도 발화하지 않으며, 티커 오브젝트도 생성되지 않습니다. 에디터 툴링이나 자동화 테스트에서 애니메이션을 끌 때 유용합니다. no-op 버전도 입력은 계속 검증합니다: null onUpdate, 유효하지 않은 Clock이나 EaseType, NaN·무한대·음수 durationSeconds는 여전히 예외를 던집니다 — 애니메이션을 꺼도 버그는 계속 보입니다.
흔한 함정
- 올바른 클럭을 고르세요. 잘못된 클럭을 골라도 오류는 아니지만 애니메이션의 느낌이 어긋납니다 — 예를 들어
Clock.UI에 바인딩된 게임플레이 애니메이션은 일시정지 중에도 계속 움직입니다. 각 클럭이 일시정지와 슬로 모션에서 어떻게 동작하는지는 Time 서비스를 보세요. - Quaternion 이징은 오버슈트를 클램프합니다. 오버슈트 커브(
InBack,OutBack,InElastic,OutElastic)는 눈에 보이는 회전 오버슈트를 만들지 않습니다.Quaternion.Slerp가 계수를 0–1 범위로 클램프하기 때문입니다. 오버슈트 구간 동안 회전은 끝 값에 머뭅니다. - 취소는 완료와 다릅니다. 트윈 토큰을 dispose하면 조용히 취소됩니다 —
onComplete는 발화하지 않습니다. 지속 시간의 끝에 도달했을 때는onComplete가 발화합니다. - 델리게이트 할당은 여러분의 비용입니다. 서비스는 내부 트윈 슬롯을 풀링하지만,
onUpdate람다(그리고customEase클로저)는 호출마다 여러분이 할당합니다. 할당이 없어야 하는 타이트한 루프에서는 델리게이트를 필드에 한 번 저장해 두고, 새 람다를 쓰는 대신 매 호출에 그 필드를 넘기세요. - 완료된 뒤의 토큰을 붙들지 마세요. 끝난 트윈의 슬롯은 이후의 트윈에 재사용됩니다. 오래된 토큰은 감지되어 무시되므로 늦게 dispose해도 해롭지는 않지만, 붙들고 있다는 것 자체가 수명 버그의 징후입니다. 발사 후 잊는(fire-and-forget) 트윈은 토큰을 저장할 필요가 아예 없습니다.
관련 페이지
- Time — 트윈이 바인딩되는 클럭
- Tween Sequencing — 순차·병렬 트윈 타임라인
- Scheduler — 같은 클럭 위의 지연과 반복 타이머