Files
XRLib/Assets/Scripts/NHN/ScrollMoveTo.cs
2025-08-08 18:33:29 +09:00

227 lines
7.6 KiB
C#

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