namespace Gpm.Ui { using UnityEngine; using MoveToType = InfiniteScroll.MoveToType; /// /// 스크롤 위치를 제어하기 위한 인터페이스입니다. /// InfiniteScroll과 같이 스크롤 기능이 있는 클래스에서 이 인터페이스를 구현합니다. /// public interface IMoveScroll { /// /// 현재 스크롤 위치를 반환합니다. /// Vector2 GetScrollPosition(); /// /// 스크롤 위치를 설정합니다. /// void SetScrollPosition(Vector2 position); /// /// 특정 아이템 인덱스로 이동할 위치를 계산하여 반환합니다. /// /// 이동할 아이템의 인덱스 /// 아이템을 정렬할 위치(상단, 중앙, 하단) Vector2 GetMovePosition(int itemIndex, MoveToType moveToType); /// /// 전체 스크롤 범위의 특정 비율로 이동할 위치를 계산하여 반환합니다. /// /// 이동할 비율 (0.0 ~ 1.0) Vector2 GetMovePosition(float scrollRate); } /// /// 특정 위치로 스크롤을 애니메이션과 함께 부드럽게 이동시키는 컴포넌트입니다. /// InfiniteScroll과 같이 IMoveScroll 인터페이스를 구현한 컴포넌트가 있는 게임 오브젝트에 추가하여 사용합니다. /// /// --- 샘플 코드 --- /// /// // 이동을 원하는 스크롤이 있는 GameObject를 찾습니다. /// GameObject scrollObject = GameObject.Find("InfiniteScroll"); /// /// // ScrollMoveTo 컴포넌트가 없으면 추가하고, 있으면 가져옵니다. /// ScrollMoveTo moveTo = scrollObject.GetComponent(); /// if (moveTo == null) /// { /// moveTo = scrollObject.AddComponent(); /// } /// /// // 예제 1: 10번 아이템의 중앙으로 0.5초 동안 이동 /// moveTo.Set(10, MoveToType.MOVE_TO_CENTER, 0.5f); /// moveTo.Play(); /// /// // 예제 2: 스크롤 전체의 80% 위치로 0.3초 동안 이동 /// moveTo.Set(0.8f, 0.3f); /// moveTo.Play(); /// /// [DisallowMultipleComponent] public class ScrollMoveTo : MonoBehaviour { /// /// 스크롤 이동 목표를 지정하는 방식입니다. /// public enum ScrollType { /// /// 아이템의 인덱스를 기준으로 이동합니다. /// INDEX, /// /// 전체 스크롤의 비율(0.0~1.0)을 기준으로 이동합니다. /// RATE } private IMoveScroll scroll; private void OnEnable() { if (scroll == null) { scroll = GetComponent(); } } /// /// 스크롤 이동 목표를 설정합니다. (인덱스 또는 비율) /// [Tooltip("스크롤 이동 목표를 설정합니다. (인덱스 또는 비율)")] public ScrollType scrollType; /// /// 이동할 대상 아이템의 인덱스입니다. (scrollType이 INDEX일 때 사용) /// [Tooltip("이동할 대상 아이템의 인덱스입니다. (scrollType이 INDEX일 때 사용)")] public int itemIndex; /// /// 아이템을 화면의 어느 위치에 맞출지 결정합니다. (scrollType이 INDEX일 때 사용) /// [Tooltip("아이템을 화면의 어느 위치에 맞출지 결정합니다. (scrollType이 INDEX일 때 사용)")] public MoveToType moveToType; /// /// 이동할 스크롤의 비율입니다. (0.0 = 시작, 1.0 = 끝) (scrollType이 RATE일 때 사용) /// [Tooltip("이동할 스크롤의 비율입니다. (0.0 = 시작, 1.0 = 끝) (scrollType이 RATE일 때 사용)")] [Range(0f, 1f)] public float scrollRate = 0; /// /// 목표 위치까지 이동하는 데 걸리는 시간(초)입니다. /// [Tooltip("목표 위치까지 이동하는 데 걸리는 시간(초)입니다.")] public float time = 0.3f; /// /// 이동 애니메이션의 속도 변화를 제어하는 커브입니다. /// [Tooltip("이동 애니메이션의 속도 변화를 제어하는 커브입니다.")] public AnimationCurve curve = AnimationCurve.EaseInOut(0, 0, 1, 1); /// /// 이동이 완료된 후 이 컴포넌트를 자동으로 파괴할지 여부입니다. /// [Tooltip("이동이 완료된 후 이 컴포넌트를 자동으로 파괴할지 여부입니다.")] public bool autoDestory = false; private float rate = 0; private Vector2 start; /// /// 특정 아이템 인덱스로 이동하도록 설정합니다. /// /// 이동할 아이템 인덱스 /// 아이템 정렬 위치 /// 이동 시간(초) public void Set(int itemIndex, MoveToType moveToType, float time) { this.scrollType = ScrollType.INDEX; this.itemIndex = itemIndex; this.moveToType = moveToType; this.time = time; } /// /// 특정 비율 위치로 이동하도록 설정합니다. /// /// 이동할 비율 (0.0 ~ 1.0) /// 이동 시간(초) public void Set(float scrollRate, float time) { this.scrollType = ScrollType.RATE; this.scrollRate = scrollRate; this.time = time; } /// /// 설정된 값에 따라 스크롤 이동 애니메이션을 시작합니다. /// public void Play() { rate = 0; enabled = true; } public void Update() { if (scroll == null) { return; } if (rate == 0) { start = scroll.GetScrollPosition(); } if (time > 0) { rate += Time.deltaTime / time; } else { rate = 1; } Vector2 end; if (scrollType == ScrollType.INDEX) { end = scroll.GetMovePosition(itemIndex, moveToType); } else if (scrollType == ScrollType.RATE) { end = scroll.GetMovePosition(scrollRate); } else { end = start; rate = 1; } if (rate < 1) { scroll.SetScrollPosition(Vector2.Lerp(start, end, curve.Evaluate(rate))); } else { scroll.SetScrollPosition(end); rate = 0; if (autoDestory == true) { Destroy(this); } enabled = false; } } } }