LitMotion 은 트윈 하나를 구조체 배열의 한 칸으로 만든다
Esc

    LitMotion 은 트윈 하나를 구조체 배열의 한 칸으로 만든다

    2026년 10월 18일 수정–Unity라이브러리트윈
    IEnumerator MoveCo(Vector3 from, Vector3 to, float duration)
    {
        for (float e = 0; e < duration; e += Time.deltaTime)
        {
            transform.position = Vector3.Lerp(from, to, e / duration);
            yield return null;
        }
        transform.position = to;
    }

    버튼 자리에서 인벤토리 칸으로 아이콘을 날리는 일을 코루틴으로 쓰면 부를 때마다 객체가 생기고, 멈추려면 Coroutine 참조를 따로 들고 있어야 합니다. Update 에서 손으로 보간하면 할당은 없지만 움직일 값마다 필드가 늘어납니다.

    LitMotion 은 트윈 하나를 객체가 아니라 구조체 배열의 한 칸으로 만들고, 그 배열을 Burst Job 으로 한꺼번에 계산합니다. 사용자는 칸을 가리키는 정수 핸들만 받습니다. 기준 판본은 2.0.2 입니다.

    기존 세 방법은 각자 빈자리가 있다

    같은 일, “0.5초 동안 위로 1만큼 올린다” 를 세 방법과 LitMotion 으로 나란히 놓습니다.

    • 코루틴. 이터레이터 메서드는 컴파일러가 클래스로 만들어서 부를 때마다 객체가 생깁니다. 이징 식도 매번 손으로 씁니다.
    • Update 보간. 할당은 없지만 값 하나에 필드 네다섯 개가 붙고, 같은 코드를 컴포넌트마다 복사합니다.
    • Animator. 끝값을 편집할 때 찍어 두는 방식이라 실행 중에 정해지는 이동에는 맞지 않습니다.

    LitMotion 은 “무엇을, 어디서 어디까지, 몇 초 동안, 어떤 곡선으로” 를 한 줄로 받고, 부를 때 할당하지 않습니다.

    모션은 객체가 아니라 배열의 한 칸이다

    “할당 없음” 을 지키려면 트윈을 클래스로 만들 수 없습니다. 그래서 모션 하나가 unmanaged 구조체 하나입니다.

    // Runtime/Internal/MotionData.cs
    internal struct MotionData<TValue, TOptions>
        where TValue : unmanaged
        where TOptions : unmanaged, IMotionOptions
    {
        public MotionData Core;     // 상태, 시간, 길이, 이징, 루프
        public TValue StartValue;
        public TValue EndValue;
        public TOptions Options;
    }

    같은 값 타입의 모션들은 이 구조체가 빈틈없이 늘어선 평범한 C# 배열 하나에 모입니다. 콜백처럼 참조 타입이어야 하는 것은 옆 배열의 같은 번호 칸에 둡니다. 사용자가 받는 MotionHandle 은 그 칸을 가리키는 정수 셋(StorageId, Index, Version)이라 필드에 담고 복사해도 할당이 없습니다.

    계산은 Burst Job 이, 대입은 메인 스레드가 한다

    LitMotion 은 ECS 를 쓰지 않고 DOTS 의 아래쪽 조각인 Burst, Job System, Collections, Mathematics 만 가져왔습니다. 시간 전진과 이징, 보간은 배열을 통째로 Job 에 넘겨 여러 코어로 나눠 계산하고, transform.position = x 같은 대입은 Job 이 끝난 뒤 메인 스레드에서 합니다. Update 타이밍의 모션 한 무리가 한 프레임에 거치는 길입니다.

    // Runtime/Internal/UpdateRunner.cs
    job.Schedule(count, 16).Complete();

    Job 을 예약한 그 줄에서 끝나기를 기다립니다. 여러 코어로 나눠 도는 for 문에 가깝고, 값은 이번 프레임 안에 대상에 들어갑니다.

    가장 짧은 예제

    using LitMotion;
    using LitMotion.Extensions;
    using UnityEngine;
    
    public class PopUp : MonoBehaviour
    {
        [SerializeField] CanvasGroup group;
    
        void Start()
        {
            var p = transform.position;
    
            LMotion.Create(p, p + Vector3.up, 0.5f)   // 설정을 모으는 빌더
                .WithEase(Ease.OutQuad)
                .BindToPosition(transform)            // 여기서 모션이 만들어지고 핸들이 돌아온다
                .AddTo(gameObject);                   // 이 오브젝트가 파괴되면 취소
    
            LMotion.Create(0f, 1f, 0.3f)
                .Bind(group, static (x, g) => g.alpha = x)   // 확장 메서드가 없는 값은 state 로
                .AddTo(gameObject);
        }
    }

    두 모션은 기본 스케줄러를 따라 Update 타이밍에 Time.timeScale 을 따르는 시간으로 돕니다. 바꾸려면 WithScheduler(MotionScheduler.UpdateIgnoreTimeScale) 처럼 지정합니다.

    주의할 점

    1. 편집할 때 모양이 정해지는 연출은 Animator 에 둔다

    안 지키면 생기는 문제. 캐릭터 동작처럼 키프레임이 정해진 연출을 LitMotion 모션 여러 개로 옮기면, 클립 하나로 끝날 일을 코드로 시간표를 짜서 유지하게 됩니다.

    이렇게 쓴다. 시작값과 끝값이 실행 중에 정해지는 이동, 크기, 색 변화에 LitMotion 을 씁니다. 모양이 고정된 연출은 Animator 에 둡니다.

    2. 모션은 게임오브젝트가 꺼져도 멈추지 않는다

    안 지키면 생기는 문제. 코루틴은 그것을 돌리던 게임오브젝트가 꺼지면 같이 멈춥니다. LitMotion 모션은 PlayerLoop 에 꽂힌 LitMotion 이 돌리므로 주인이 없습니다. 대상이 파괴된 뒤에도 모션은 남아서 파괴된 오브젝트에 값을 쓰려 합니다.

    이렇게 쓴다. 모션을 만들 때 AddTo(gameObject) 로 수명을 게임오브젝트에 묶습니다. 따로 멈춰야 하면 받은 핸들을 필드에 두고 TryCancel() 합니다.

    정리

    LitMotion 은 트윈 하나를 구조체 배열의 한 칸으로 만들고, 그 배열을 Burst Job 으로 계산하는 트윈 라이브러리입니다.

    • 코루틴은 호출마다 객체를 만들고, Update 보간은 상태를 손으로 들고, Animator 는 실행 중에 정해지는 값을 못 다룹니다.
    • 모션은 unmanaged 구조체 한 칸이고 사용자는 정수 셋짜리 핸들만 받아 할당이 없습니다.
    • 계산은 Job 이 여러 코어로 나눠 하고 그 자리에서 기다리며, 대입은 메인 스레드가 합니다.