유니티 RPG - 15. 인벤토리-3(마우스 이벤트-1)
Intro
이번 포스팅에서는 인벤토리내에서 일어나는 마우스 이벤트들을 구현했습니다.
마우스에 의한 이벤트는 InventoryUI 스크립트에서 구현했습니다.
InventoryUI
InventoryUI 스크립트에서 GraphicRaycaster를 이용하여 포인터의 이벤트를 직접 구현했습니다.
먼저, 인벤토리에 있는 아이템을 마우스로 클릭하고, 드래그하고, 클릭한뒤 떼는이벤트가 있을것이고(예를들어 드래그앤드롭으로 아이템 위치변경)
또는 저번포스팅에서 만들었던 슬롯의 하이라이트 효과를 내기위해 마우스포인터가 슬롯에 올라갔다 나갔다할때의 이벤트가 있을것입니다.
따라서 우리는 마우스포인터의 Down, Drag, Up 이벤트와 Enter&Exit 이벤트도 필요할것입니다.
멤버변수
private GraphicRaycaster gr;
private PointerEventData ped;
private List<RaycastResult> rrList; // 마우스 위치에서 감지된 UI 정보
private ItemSlotUI pointerOverSlot; // 현재 마우스 포인터가 위치한 곳의 슬롯
private ItemSlotUI beginDragSlot; // 마우스 드래그를 시작한 슬롯
private Transform beginDragIconTransform; // 마우스 드래그를 시작한 슬롯의 아이콘
private int leftClick = 0; // 좌클릭 = 0
private int rightClick = 1; // 우클릭 = 0
private bool showHighlight = true; // 하이라이트 보이기
private Vector3 beginDragIconPoint; // 마우스 드래그를 시작한 아이콘 위치
private Vector3 beginDragCorsorPoint; // 마우스 드래그를 시작한 커서 위치
private int beginDragSlotSiblingIndex; // 마우스 드래그를 시작한 슬롯의 UI 순서
- GraphicRaycaster는 UI 요소를 클릭했는지 확인하기 위한 레이캐스터입니다.
- 마우스 클릭이나 터치 입력이 UI에 닿았는지 판단합니다.
- PointerEventData는 마우스 포인터 또는 터치 정보를 담는 데이터구입니다.
- 마우스 위치를 추적하기위해 사용했습니다.
- UnityEngine.EventSystems 네임스페이스를 추가해주어야합니다.
- rrList는 GraphicRaycaster를 통해 감지된 결과를 담을 리스트입니다.
- 마우스 위치에서 감지된 UI요소들이 저장됩니다.
이제 각 이벤트들을 위한 함수들을 구현해주어야합니다.
마우스 이벤트 함수
#region ** 마우스 이벤트 함수들 **
// 마우스 올라갈때 나갈때 처리
private void OnPointerEnterAndExit()
{
}
// 마우스 눌렀을 때 처리
private void OnPointerDown()
{
}
// 마우스 드래그중일 때 처리
private void OnPointerDrag()
{
}
// 마우스 뗐을 때 처리
private void OnPointerUp()
{
}
// 마우스 드래그 종료 처리
private void EndDrag()
{
}
#endregion
각 함수를 구현하기전에 마우스 위치를 추적하고 해당 마우스위치의 UI 정보를 가져오는 함수를 만들었습니다.
마우스 위치추적 및 커서위치의 UI정보 가져오기
private void Init()
{
TryGetComponent(out gr);
if (gr == null)
gr = gameObject.AddComponent<GraphicRaycaster>();
ped = new PointerEventData(EventSystem.current);
rrList = new List<RaycastResult>(10);
}
private void Update()
{
// 마우스 위치 추적
ped.position = Input.mousePosition;
}
// 레이캐스팅한 첫 UI요소의 컴포넌트를 가져오기
private T RaycastAndgetFirstComponent<T>() where T : Component
{
// 리스트 초기화
rrList.Clear();
// 현재 마우스 위치에서 감지된 UI요소 저장
gr.Raycast(ped, rrList);
// 없으면 null
if (rrList.Count == 0)
return null;
return rrList[0].gameObject.GetComponent<T>();
}
- RaycastAndgetFirstComponent 함수는 현재 마우스위치에서 감지된 UI 요소의 컴포넌트를 가져오는 함수입니다.
- 이 함수를 통해서 마우스위치에있는 아이템슬롯의 정보를 가져올 수 있도록 했습니다.
마우스 이벤트 함수 세부구현
#region ** 마우스 이벤트 함수들 **
// 마우스 올라갈때 나갈때 처리
private void OnPointerEnterAndExit()
{
// 이전 프레임 슬롯
var prevSlot = pointerOverSlot;
// 현재 프레임 슬롯
var curSlot = pointerOverSlot = RaycastAndgetFirstComponent<ItemSlotUI>();
// 마우스 올라갈 때
if(prevSlot == null)
{
if(curSlot != null)
{
OnCurrentEnter();
}
}
// 마우스 나갈 때
else
{
if(curSlot == null)
{
OnPrevExit();
}
// 다른 슬롯으로 커서 옮길때
else if(prevSlot != curSlot)
{
OnPrevExit();
OnCurrentEnter();
}
}
void OnCurrentEnter()
{
if (showHighlight)
curSlot.Highlight(true);
}
void OnPrevExit()
{
prevSlot.Highlight(false);
}
}
// 마우스 눌렀을 때 처리
private void OnPointerDown()
{
// 마우스 좌클릭(Holding)
if(Input.GetMouseButtonDown(leftClick))
{
// 시작 슬롯
beginDragSlot = RaycastAndgetFirstComponent<ItemSlotUI>();
// 슬롯에 아이템이 있을 때
if(beginDragSlot != null && beginDragSlot.HasItem && beginDragSlot.IsAccessible)
{
// 드래그 위치,참조
beginDragIconTransform = beginDragSlot.IconRect.transform;
beginDragIconPoint = beginDragIconTransform.position;
beginDragCursorPoint = Input.mousePosition;
beginDragSlotSiblingIndex = beginDragSlot.transform.GetSiblingIndex();
beginDragSlot.transform.SetAsLastSibling();
beginDragSlot.SetHighlightOnTop(false);
}
else
{
beginDragSlot = null;
}
}
// 마우스 우클릭
else if(Input.GetMouseButtonDown(rightClick))
{
}
}
// 마우스 드래그중일 때 처리
private void OnPointerDrag()
{
// 드래그중이 아닐때
if (beginDragSlot == null) return;
if(Input.GetMouseButton(leftClick))
{
// 슬롯 아이콘 위치 업데이트
beginDragIconTransform.position = beginDragIconPoint + (Input.mousePosition - beginDragCursorPoint);
}
}
// 마우스 뗐을 때 처리
private void OnPointerUp()
{
if(Input.GetMouseButtonUp(leftClick))
{
// 기존으로 복원
if(beginDragSlot != null)
{
// 위치 복원
beginDragIconTransform.position = beginDragIconPoint;
// UI 순서 복원
beginDragSlot.transform.SetSiblingIndex(beginDragSlotSiblingIndex);
// 드래그 완료
EndDrag();
// 하이라이트 이미지를 아이콘보다 앞에
beginDragSlot.SetHighlightOnTop(true);
// 참조 제거
beginDragSlot = null;
beginDragIconTransform = null;
}
}
}
// 마우스 드래그 종료 처리(아이템 수량 나누기, 교환, 이동, 버리기 등)
private void EndDrag()
{
}
#endregion
각 이벤트함수 설명
함수를 하나씩 정리해보았습니다.
-
OnPointerEnterAndExit : 마우스 포인터가 슬롯에 올라가고 나갈때의 이벤트입니다.
prevSlot 은 이전에 마우스위치에 있던 슬롯의 정보 curSlot 은 현재 마우스위치에 있던 슬롯의 정보입니다.
따라서 최초에는 아무 데이터가 없는상태(null)이며, 그 후 마우스커서가 슬롯에 위치하게되면 curslot에 해당 슬롯정보가 담기게됩니다.
처음 포인터가 슬롯에 올라갈경우(prev=null, curslot=해당슬롯정보) 내부 함수 OnCurrentEnter() 호출을 통해 하이라이트효과를 동작시킵니다.
또한 슬롯에 위치했던 마우스커서가 다른곳으로 나갈때는 두가지 경우가 있습니다.
- 슬롯에서 바로 다른 슬롯으로 나갈 때(prevSlot(이전슬롯) != curSlot(현재슬롯))
- 아무것도 아닌곳으로 나갈 때(prevSlot(이전슬롯) curSlot=null)
굳이 나눈 이유는 혹시 애니메이션이나 다른 데이터업데이트가 필요할경우가 있을수도있기 때문입니다. 각 경우에서 하이라이트 효과를 끄고 켜줍니다.
-
OnPointerDown : 마우스 클릭(좌,우)시 이벤트(드래그포함)입니다.
슬롯을 좌클릭하는경우는 해당 슬롯의 아이템을 끌어서(드래그) 놓는 경우가 있습니다.
- 다른 빈 슬롯으로 옮기거나
- 다른 슬롯의 아이템과 자리를 바꾸거나
- 다른 슬롯의 아이템에 합치거나(같은 아이템인경우)
- 버리거나
OnPointerDown() 함수에서 위 4가지 이벤트를 처리하지는 않고, 단지 드래그하는 슬롯정보를 기억해둡니다.
드래그할 슬롯 아이콘의 처음위치, 커서위치, 우선순위(SiblingIndex)등을 기억해둡니다.
우클릭시에 발생할 이벤트인 아이템사용은 비워두었습니다.
- OnPointerDrag : 마우스 좌클릭 후 드래그시 발생하는 이벤트입니다.
드래그할 때 아이콘이 마우스커서를 따라오도록 하는 함수입니다.
-
OnPointerUp : 마우스 클릭을 뗄 때 발생하는 이벤트입니다.
먼저 좌클릭 이벤트(드래그)는 드래그중이던 아이템 아이콘위치를 우선 복원시킵니다.
UI순서(SiblingIndex)도 복원시킵니다.
EndDrag() 함수는 위에서 설명한 4가지 이벤트를 경우에맞게 실행시킵니다.(아직 미구현)
마지막으로 참조하고있던 슬롯정보를 제거합니다.
-
EndDrag : 마우스 드래그를 뗄 때 발생하는 이벤트입니다.
OnPointerUp 함수와는 다르게 클릭을 떼는 커서위치에 따른 이벤트가 발생합니다.
- 다른 빈 슬롯으로 옮기거나
- 다른 슬롯의 아이템과 자리를 바꾸거나
- 다른 슬롯의 아이템에 합치거나(같은 아이템인경우)
- 버리거나
에 대한 이벤트를 구현해줄 예정입니다.
댓글남기기