playback 기능 추가
This commit is contained in:
175
Assets/Scripts/UVC/UI/UIDragger.cs
Normal file
175
Assets/Scripts/UVC/UI/UIDragger.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace UVC.UI
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// UI 요소를 마우스로 드래그하여 이동할 수 있게 만드는 컴포넌트입니다.
|
||||
/// IBeginDragHandler, IDragHandler, IEndDragHandler 인터페이스를 구현하여 드래그 이벤트를 처리합니다.
|
||||
/// 이 컴포넌트는 드래그될 UI 요소의 자식 오브젝트(예: 창의 헤더 영역)에 부착되어야 합니다.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <b>사용 예제:</b>
|
||||
/// 1. 드래그하고 싶은 창(Panel) UI를 만듭니다.
|
||||
/// 2. 해당 창의 자식으로 드래그 핸들 역할을 할 UI(예: Image)를 만들고, 이 오브젝트에 `UIDragger` 컴포넌트를 추가합니다.
|
||||
/// 3. 아래와 같은 컨트롤러 스크립트를 만들어 창에 추가하고, Inspector 창에서 `draggerHandle`과 `windowPanel`을 연결해줍니다.
|
||||
/// <code>
|
||||
/// using UnityEngine;
|
||||
/// using UVC.UI;
|
||||
///
|
||||
/// public class DraggableWindowController : MonoBehaviour
|
||||
/// {
|
||||
/// // UIDragger 컴포넌트가 부착된 드래그 핸들 오브젝트
|
||||
/// public UIDragger draggerHandle;
|
||||
///
|
||||
/// void Start()
|
||||
/// {
|
||||
/// // 드래그 시작 이벤트 구독
|
||||
/// draggerHandle.onBeginDragHandler += () =>
|
||||
/// {
|
||||
/// Debug.Log("창 드래그가 시작되었습니다!");
|
||||
/// };
|
||||
///
|
||||
/// // 드래그 종료 이벤트 구독
|
||||
/// draggerHandle.OnEndDragHandler += pos =>
|
||||
/// {
|
||||
/// Debug.Log($"창 드래그가 종료되었습니다! 최종 위치: {pos}");
|
||||
/// };
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public class UIDragger : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
|
||||
{
|
||||
[Header("드래그 설정")]
|
||||
[SerializeField]
|
||||
[Tooltip("드래그 가능한 영역을 지정합니다. 이 영역 내에서 드래그가 가능합니다.")]
|
||||
private RectTransform dragArea; // 드래그가 가능한 영역
|
||||
[SerializeField]
|
||||
[Tooltip("드래그할 UI 요소를 지정합니다. 이 요소가 실제로 드래그됩니다.")]
|
||||
private RectTransform dragObject; // 실제로 드래그될 UI 요소 (예: 창 전체)
|
||||
[SerializeField]
|
||||
[Tooltip("드래그 시작 시 해당 UI 요소를 맨 앞으로 가져올지 여부를 설정합니다.")]
|
||||
private bool topOnDrag = true; // 드래그 시작 시 맨 앞으로 가져올지 여부
|
||||
[SerializeField]
|
||||
[Tooltip("드래그 영역 제한 시 사용할 최소 높이값")]
|
||||
private float yMinHeight = 30;
|
||||
|
||||
private Vector2 originalLocalPointerPosition; // 드래그 시작 시 마우스 포인터의 로컬 위치
|
||||
private Vector3 originalPanelLocalPosition; // 드래그 시작 시 패널의 로컬 위치
|
||||
|
||||
/// <summary>
|
||||
/// 드래그가 끝났을 때 발생하는 이벤트입니다. 최종 위치 정보를 전달합니다.
|
||||
/// </summary>
|
||||
public Action<Vector3> OnEndDragHandler { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 드래그가 시작될 때 발생하는 액션입니다.
|
||||
/// </summary>
|
||||
public Action onBeginDragHandler;
|
||||
|
||||
|
||||
// 원래의 형제 순서(UI 렌더링 순서)
|
||||
private int baseSibling;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
// dragObject가 설정되지 않았다면, 부모를 드래그 대상으로 설정
|
||||
if (dragObject == null)
|
||||
{
|
||||
dragObject = transform.parent as RectTransform;
|
||||
if (dragObject == null)
|
||||
{
|
||||
Debug.LogError("<b>[UIDragger]</b> 드래그할 객체(dragObject)를 찾을 수 없습니다. 부모가 RectTransform이 아닙니다.", this);
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// dragArea가 설정되지 않았다면, 최상위 Canvas를 드래그 영역으로 설정
|
||||
if (dragArea == null)
|
||||
{
|
||||
dragArea = GetComponentInParent<Canvas>()?.transform as RectTransform;
|
||||
if (dragArea == null)
|
||||
{
|
||||
Debug.LogError("<b>[UIDragger]</b> 드래그 영역(dragArea)으로 사용할 Canvas를 찾을 수 없습니다.", this);
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 드래그가 시작될 때 호출됩니다. (IBeginDragHandler)
|
||||
/// </summary>
|
||||
public void OnBeginDrag(PointerEventData data)
|
||||
{
|
||||
if (data.button != PointerEventData.InputButton.Left) return;
|
||||
|
||||
originalPanelLocalPosition = dragObject.localPosition;
|
||||
baseSibling = dragObject.GetSiblingIndex();
|
||||
|
||||
RectTransformUtility.ScreenPointToLocalPointInRectangle(dragArea, data.position, data.pressEventCamera, out originalLocalPointerPosition);
|
||||
|
||||
if (topOnDrag)
|
||||
{
|
||||
dragObject.SetAsLastSibling();
|
||||
}
|
||||
onBeginDragHandler?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 드래그 중일 때 매 프레임 호출됩니다. (IDragHandler)
|
||||
/// </summary>
|
||||
public void OnDrag(PointerEventData data)
|
||||
{
|
||||
if (data.button != PointerEventData.InputButton.Left) return;
|
||||
|
||||
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(dragArea, data.position, data.pressEventCamera, out Vector2 localPointerPosition))
|
||||
{
|
||||
Vector3 offsetToOriginal = localPointerPosition - originalLocalPointerPosition;
|
||||
dragObject.localPosition = originalPanelLocalPosition + offsetToOriginal;
|
||||
}
|
||||
|
||||
ClampToArea();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 드래그가 끝났을 때 호출됩니다. (IEndDragHandler)
|
||||
/// </summary>
|
||||
public void OnEndDrag(PointerEventData eventData)
|
||||
{
|
||||
if (eventData.button != PointerEventData.InputButton.Left) return;
|
||||
|
||||
if (topOnDrag)
|
||||
{
|
||||
dragObject.SetSiblingIndex(baseSibling);
|
||||
}
|
||||
OnEndDragHandler?.Invoke(dragObject.anchoredPosition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI 요소가 드래그 영역 내에 있도록 위치를 제한합니다.
|
||||
/// </summary>
|
||||
private void ClampToArea()
|
||||
{
|
||||
Vector3 pos = dragObject.localPosition;
|
||||
Rect dragObjectRect = dragObject.rect;
|
||||
Rect dragAreaRect = dragArea.rect;
|
||||
|
||||
// Pivot을 기준으로 최소/최대 위치를 계산합니다.
|
||||
float minX = dragAreaRect.xMin - dragObjectRect.xMin;
|
||||
float maxX = dragAreaRect.xMax - dragObjectRect.xMax;
|
||||
float minY = dragAreaRect.yMin - dragObjectRect.yMin;
|
||||
float maxY = dragAreaRect.yMax - dragObjectRect.yMax;
|
||||
|
||||
pos.x = Mathf.Clamp(pos.x, minX, maxX);
|
||||
pos.y = Mathf.Clamp(pos.y, minY, maxY - yMinHeight);
|
||||
|
||||
dragObject.localPosition = pos;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user