[Unity] 드래그 앤 드롭 시스템 만들기: ScrollView를 반영한 드래그 앤 드롭 시스템

ggm-_-·2024년 12월 16일
2

TIL (Tody I Learn)

목록 보기
44/51

2024.12.16(월)

이전 글: [Unity] 드래그 앤 드롭 시스템 만들기 : UI to World & World to World

이전에 만들었던 드래그 앤 드롭 시스템에 사소한 문제가 있었다.
바로, 드래그 앤 드롭 시스템이 ScrollView의 Scroll 시스템을 가린다는 것이다.
찾아보니까 ScrollView의 시스템도 IBeginDragHandler, IDragHandler, IEndDragHandler에 의해 조절이 된다는 것을 알게 됐다.

그래서, 이것을 적절히 이용해서 드래그 앤 드롭 시스템을 ScrollView의 영역을 나갔을 때만 발동되게 만들어 주었다.

ScrollView를 반영한 드래그 앤 드롭 시스템

UI에서만 일어나는 일이기 때문에, DraggableUI만 손봐주면 된다.

  • DraggableUI.cs
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class DraggableUI : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    public DraggableContent draggableContent; // 연결된 콘텐츠 설정
    [SerializeField] private ScrollRect scrollView; // ScrollView 참조 (Inspector에서 설정)

    private bool isDragging = false; // 드래그 상태 확인
    private bool isInScrollView = false; // 현재 스크롤 영역 내부인지 확인
    private PointerEventData cachedEventData; // 스크롤 이벤트 캐싱용

    public void OnBeginDrag(PointerEventData eventData)
    {
        // ScrollView 영역인지 확인
        if (scrollView != null)
        {
            isInScrollView = RectTransformUtility.RectangleContainsScreenPoint(
                scrollView.GetComponent<RectTransform>(),
                eventData.position,
                eventData.pressEventCamera
            );

            if (isInScrollView)
            {
                // ScrollView 내부라면 스크롤 이벤트를 캐싱하고 ScrollView의 OnBeginDrag 호출
                cachedEventData = eventData;
                scrollView.OnBeginDrag(eventData);
                return;
            }
        }

        // ScrollView 외부라면 드래그 시작
        isDragging = true;
        DragAndDropManager.Instance.BeginDrag(draggableContent, eventData);
    }

    public void OnDrag(PointerEventData eventData)
    {
        // 상태 전환 로직: 마우스 위치를 기반으로 상태 변경
        if (scrollView != null)
        {
            bool currentlyInScrollView = RectTransformUtility.RectangleContainsScreenPoint(
                scrollView.GetComponent<RectTransform>(),
                eventData.position,
                eventData.pressEventCamera
            );

            // ScrollView에서 Drag로 전환
            if (isInScrollView && !currentlyInScrollView)
            {
                isInScrollView = false;
                isDragging = true;

                // ScrollView 동작 종료
                scrollView.OnEndDrag(cachedEventData);

                // Drag 동작 시작
                DragAndDropManager.Instance.BeginDrag(draggableContent, eventData);
                return;
            }

            // Drag에서 ScrollView로 전환
            if (!isInScrollView && currentlyInScrollView)
            {
                isInScrollView = true;
                isDragging = false;

                // Drag 동작 종료
                DragAndDropManager.Instance.EndDrag(eventData);

                // ScrollView 동작 시작
                scrollView.OnBeginDrag(eventData);
                return;
            }
        }

        // 현재 상태에 따라 적절한 동작 수행
        if (isInScrollView)
        {
            scrollView.OnDrag(eventData); // ScrollView의 스크롤 처리
        }
        else if (isDragging)
        {
            DragAndDropManager.Instance.Drag(eventData); // Drag 처리
        }
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        // 현재 상태에 따라 동작 종료
        if (isInScrollView)
        {
            scrollView.OnEndDrag(eventData);
        }
        else if (isDragging)
        {
            DragAndDropManager.Instance.EndDrag(eventData);
        }

        // 상태 초기화
        isDragging = false;
        isInScrollView = false;
        cachedEventData = null;
    }
}

다음과 같이 작성하면 ScrollView 내에서는 드래그로 ScrollView가 작동하고, ScrollView를 벗어나면 드래그 앤 드롭 시스템이 작동, 그리고 다시 ScrollView 내부로 마우스가 들어오면 ScrollView가 작동하게 된다.

profile
미숙한 초보 게임 개발자

4개의 댓글

comment-user-thumbnail
2024년 12월 17일

ScrollView... 참 좋은 기능이죠

1개의 답글
comment-user-thumbnail
2024년 12월 17일

잘 보고 갑니다~

1개의 답글