코드 및 공부/데이터 관리

OnDrop이 실행되었을때 OnEndDrag가 실행되지 못하도록 하기

ekrxjvpvj0110 2024. 12. 24. 17:54

유니티 버전 - 2022.3.17f1

 

 

 

 

 

목차


  • 코드 의도
  • 문제 상황
  • 시도해본 방법들
  • 해결 과정
  • 결과
  • 마치며

 

 

 

 

 

코드 의도


드래그가 종료되었을때 성공적으로 수행된다면 OnDrop을 이용하여 성공 사운드 출력 및 아이템 교환을 하고, 실패한다면 OnEndDrag를 이용하여 실패 사운드 출력 및 DragSlot을 초기화시켜 주고 싶은 상황입니다

    /// <summary>
    /// 드래그가 UISlot이 아닌 곳에서 끝났을때 아무 작업도 수행하지 않기위해 DragSlot을 초기화시켜줌
    /// </summary>
    public void OnEndDrag(PointerEventData eventData)
    {
        if (DragSlot.Instance.draggedSlot != null)
        {
            Managers.Sound.PlaySfx(SfxEnums.ButtonClickNegative);
            DragSlot.Instance.ClearDragSlot();
        }
    }
    
    
    /// <summary>
    /// 드래그가 UISlot에서 끝났을때 SlotType을 체크하여 아이템 교체를 진행함
    /// </summary>
    public void OnDrop(PointerEventData eventData)
    {
        if (DragSlot.Instance.draggedSlot.itemSo != null)
        {
            Managers.Sound.PlaySfx(SfxEnums.ItemDropInventory);
            ChangeSlot();
        }
    }

 

 

 

 

 

문제 상황(의도와 다른 현상 발생)


성공적으로 교환이 일어났음에도 OnDrop이후 OnEndDrag가 실행되어 사운드가 두번 재생되었습니다

왜냐하면 OnEndDrag는 OnDrop의 성공 여부와 관계없이 드래그가 끝나면 항상 실행되기 때문입니다

 

 

 

 

 

시도해본 방법들

 - 아래의 방법으로는 해결할 수 없습니다, 해결 과정부터 참고 바랍니다


1. 코루틴과 플래그 이용하여 OnEndDrag의 실행 타이밍을 늦춰보았습니다

    /// <summary>
    /// 드래그가 UISlot이 아닌 곳에서 끝났을때 아무 작업도 수행하지 않기위해 DragSlot을 초기화시켜줌
    /// </summary>
    public void OnEndDrag(PointerEventData eventData)
    {
        StartCoroutine(CheckOnDroped()); // 1프레임 늦게 실행되도록 함
    }


    private IEnumerator CheckOnDroped()
    {
        yield return null;

        if (!_isDropped)
        {
            Managers.Sound.PlaySfx(SfxEnums.ButtonClickNegative);
        }

        DragSlot.Instance.ClearDragSlot();
        _isDropped = false;
    }


    /// <summary>
    /// 드래그가 UISlot에서 끝났을때 SlotType을 체크하여 아이템 교체를 진행함
    /// </summary>
    public void OnDrop(PointerEventData eventData)
    {
        if (DragSlot.Instance.draggedSlot.itemSo != null)
        {
            _isDropped = true; // 성공적으로 이루어졌을때 true로 바꿔서 if에서 걸리게 함
            ChangeSlot();
            Managers.Sound.PlaySfx(SfxEnums.ItemDropInventory);
        }
    }

 

 

 

2. 인터페이스 상속을 하지않고 메서드만 이용, 이벤트 트리거를 사용하여 실행 순서를 조절하여 보았습니다

 

 

 

 

 

해결 과정


1. 위의 두가지 방법을 이용하여 실행순서를 바꿔보았지만 제대로 동작하지 않았고, 실행순서를 확인해보니 원래 OnDrop -> OnEndDrag 순서였고, 위의 행동은 전혀 문제 해결과 관련이 없었다는것을 라는 것을 알았습니다

 

2. 그렇다면 OnDrop에서 true로 바뀐다면 OnEndDrag에서도 반영되어야 하지만 그렇지 않았습니다

 

3. 다른곳에서 문제가 있다고 생각하고 각 인터페이스를 F12를 눌러 정의를 보았습니다

IBeginDragHandler, IDragHandler, IEndDragHandler, IDropHandler

 

 

4. summary를 확인해 보고 번역해본 결과는 다음과 같습니다, BaseInputModule까지는 같지만 뒷 내용이 다릅니다

- OnEndDrag : 드래그가 종료되면 BaseInputModule에서 호출됩니다.

- OnDrop : 드롭을 허용할 수 있는 대상의 BaseInputModule에서 호출됩니다.

 

5. BaseInputModule을 검색하여보니 다음과 같은 자료를 찾을 수 있었습니다, 이벤트를 발생시킨 주체에 대한 내용으로 파악되고, BaseInputModule과 target BaseInputModule 이라는 점을 미루어 보아 OnEndDrag와 OnDrop이 동일한 스크립트에서 발생하지 않는게 아닐까 라고 생각했습니다

 

6. Scripting API에서 제공하는 BaseInputModule에 대한 정보는 너무 예전 것이라, 최신 API에서 검색해보았지만 찾을 수 없어 GPT에게 물어봤습니다, 그리고 OnDrop은 드래그 당한 슬롯의 내용이, 나머지는 드래그를 시작한 슬롯의 내용이 반영된다는 것을 알게 되었습니다, 그래서 OnDrop에서 bool 값을 바꾸어도 적용이 되지 않았던 것이였습니다

 

 

 

 

 

결과


1. 드래그를 시작할때 넘겨준 슬롯의 bool값을 참조할 수 있도록 하였습니다(원래 넘겨서 내부의 다른 것들을 사용중이였음)

    /// <summary>
    /// 마우스 드래그가 시작될때 DragSlot에 이동시키고자하는 아이템의 정보를 담음
    /// </summary>
    public void OnBeginDrag(PointerEventData eventData)
    {
        // ...
        DragSlot.Instance.uiSlot = this;
        // ...
    }

 

 

 

2. 슬롯 교환이 성공적으로 이루어 질때 직접 bool값을 수정하여주었습니다

    public void OnDrop(PointerEventData eventData)
    {
        if (DragSlot.Instance.draggedSlot.itemSo != null)
        {
            Managers.Sound.PlaySfx(SfxEnums.ItemDropInventory);
            DragSlot.Instance.uiSlot.isSuccessDrop = true; // 직접 수정
            ChangeSlot();
        }
    }

 

 

 

3. 이제 OnEndDrag에서 bool 값이 잘 반영되어 조건문을 통해 사운드를 출력할지 말지 판단할 수 있게 되었습니다

    public void OnEndDrag(PointerEventData eventData)
    {
        // ...

        if (isSuccessDrop == false)
        {
            Managers.Sound.PlaySfx(SfxEnums.ButtonClickNegative);
        }
        
        isSuccessDrop = false;
        DragSlot.Instance.ClearDragSlot();
    }

 

 

 

이상입니다.