내일배움캠프 - TIL/내일배움캠프 - TIL

내일배움캠프 31일차 - 인벤토리 아이탬 위치 바꾸기 버그

rudals4469 2025. 6. 9. 20:44

오늘은 인벤토리를 짜고 슬롯끼리 교체하는 아이템 위치 바꾸는 기능을 만들어보았는데

 

인벤토리 슬롯 인덱스가 자꾸 이상해지는 버그가 생겼다.

 

원인을 계속 추적해보니, 

 


인벤토리에 들어가는 아이템을 그리드 레이아웃 그룹으로 인벤토리에 들어가게 구현되어있는데.

 

이제 내가 드래그로 아이탬을 집었을 때, 

 

transform.SetParent(_canvas.transform); // 부모를 canvas로 옮겨서 자유롭게 움직이게 함

 

로 슬롯을 캔버스의 바로 밑의 자식으로 꺼내어 자유롭게 움직일 수 있도록 하였었다. 

 

그런데 여기서 문제가 캔버스의 자식으로 빼버리니, 그리드 레이아웃 그룹에서 빠지게 되고 다시 드래그가 완료 되었을 때

 

다시 레이아웃에 넣어주게 되니 인벤토리의 마지막 슬롯으로 들어가게 되었다.

 

transform.SetParent(_originalParent); // 원래 부모로 복귀
transform.SetSiblingIndex(_placeholder.transform.GetSiblingIndex()); // 정확한 위치 복귀

 

그래서 먼저 한 작업은 드래그 할 때 몇 번 인덱스인지 기억시켜놓고 드래그가 끝났을 때 그 인덱스로 들어갈 수 있도록 하주고

 

슬롯에서 빠질 때 임시 오브젝트인 "자리 홀더" 라는 객체를 만들어 그리드 레이아웃에서 빠져도 이 위치를 자리 홀더가 대신하게 하여 인덱스가 빠지지 않도록 설정해주고 드래그가 끝날 때 자리 복귀를 할 때 자리 홀더가 삭제 되게 구현해주었다.

 

public void OnBeginDrag(PointerEventData eventData)
{
    // 빈 슬롯은 드래그 x
    if (_slot.Item == null)
    {
        eventData.pointerDrag = null; // 드래그 자체를 안함
        return;
    }

    // 현재 부모 저장
    _originalParent = transform.parent;

    // 자리 유지용 임시 오브젝트 생성
    _placeholder = new GameObject("SlotPlaceholder");
    var rect = _placeholder.AddComponent<RectTransform>();
    rect.SetParent(_originalParent);
    rect.SetSiblingIndex(_slot.Index); // 현재 클릭 된 자리로 위치 고정
    rect.sizeDelta = _rectTransform.sizeDelta; // 사이즈로 같게 생성

    transform.SetParent(_canvas.transform); // 부모를 canvas로 옮겨서 자유롭게 움직이게 함
    _canvasGroup.blocksRaycasts = false; // 다른 슬롯이 드랍을 감지 할 수 있도록 설정
}

// 마우스 따라다니게 하기
public void OnDrag(PointerEventData eventData)
{
    if (_slot.Item == null) return;

    // 마우스 움직이 만큼 위치 갱신
    _rectTransform.anchoredPosition += eventData.delta / transform.lossyScale;
}

public void OnEndDrag(PointerEventData eventData)
{
    // 정상적으로 드래그가 완료 되었을 때
    if (_placeholder != null)
    {
        transform.SetParent(_originalParent); // 원래 부모로 복귀
        transform.SetSiblingIndex(_placeholder.transform.GetSiblingIndex()); // 정확한 위치 복귀
        Destroy(_placeholder); // 임시 오브젝트 삭제
        _placeholder = null;
    }
    else
    {
        transform.SetParent(_originalParent); // 드래그 자체를 무효화
    }

    _rectTransform.anchoredPosition = Vector2.zero; // 위치 초기화
    _canvasGroup.blocksRaycasts = true; // 다시 상호작용 가능하게 설정
}

 

자리 유지용으로 _placeholder을 만들어주어 슬롯에서 아이탬이 빠져도 빠진 인덱스는 _placeholder가 채워주고 있으므로 실질적으로 인덱스가 어긋나지 않도록 해결 해주었다.