만든거 미리보기
카드게임을 만들어보기로 했다. 근데 그러려면 일단 자유로운 카드의 이동부터 만들어야겠다는 생각을 했음.
일단 정렬을 위해 최상위 오브젝트에 LayoutGroup
컴포넌트를 사용하고, 그 아래엔 슬롯들을 만들어 드래그 할 때와 그 종료시에도 그룹은 항상 일정한 간격 유지하며 정렬되어 있을 수 있도록 만들었다. 내부 오브젝트에는 유니티 이벤트 핸들러의 드래그 핸들러 인터페이스를 이용해서 드래그중 포인터의 위치로, 종료시 localPos
를 0으로 간단하게 만들어봤음. 이때 가장 먼저 발생한 문제점은 뭐였냐면,
바로 하이라키 계층구조 때문에 뒤에있는 오브젝트들은 드래그시에 정상적으로 가장 전면에 랜더링되지만, 1번 카드는 2, 3, 4, 5번 모든 카드쪽으로 드래그 할 때 가장 뒤쪽에 보인다는 것이었음. 이건 간단하게 슬롯 바깥쪽에 새로운 부모를 만들어두고 드래그 시작시에 부모를 그쪽으로 옮겨주는것으로 해결했다.
private Transform dragParent;
private CardSlot originalSlot;
private void OnPointerDownCard(DraggableUIObject drag)
{
originalSlot = drag.transform.GetComponentInParent<CardSlot>(); //이건 돌아갈 때 원래 위치로 돌아가기 위해 저장해놨다.
drag.transform.SetParent(dragParent);
}
하이라키에선 저렇게 슬롯그룹 외부로 빼두어 가장 드래그중인 오브젝트가 화면 가장 위쪽에 위치할 수 있도록 했다.
사실 이건 발라트로를 보고 만들어봐야겠다고 마음먹었다. 발라트로는 카드를 드래그중일 때 드래그중이지 않은 나머지 카드들도 드래그중인 카드의 영향을 받아 자동으로 정렬이 된다. 참으로 만족스러운 피드백인데, 이런게 있으면 따라 안만들어 볼 수 없지. 일단 드래그중인 카드의 x좌표값을 나머지 카드들과 비교해서, 커지거나 작아질 경우 비어있는 슬롯으로 부모를 옮기면 될 것 같다고 생각했다.
public class CardSlot
{
public bool isEmpty { get {return transform.childCount == 0; } }
}
일단 슬롯 외부에서 빈 슬롯인지 확인하기 위해 자식의 개수로 슬롯이 현재 차있는지 확인한 후, 상위 그룹에서 슬롯 배열을 순회하며 현재 드래그중인 카드의 x값과 슬롯에 있는 카드들의 x값을 비교해주기로 했다.
private void OnDragCard(DraggableUIObject drag)
{
float draggingCardX = drag.transform.position.x; // 현재 드래그중인 카드의 x좌표
for (int i = 0; i < cardSlots.Length; i++)
{
if (cardSlots[i].isEmpty) continue; // 빈 슬롯이라면 건너뛰기
float slotCardX = cardSlots[i].slotCard.transform.position.x;
if (draggingCardX < slotCardX && i < cardSlots.Length - 1)
{
if (cardSlots[i + 1].isEmpty)
{
DraggableUIObject card = cardSlots[i].slotCard;
card.transform.SetParent(cardSlots[i + 1].transform);
card.SetLocalPosZero();
break;
}
}
else if (draggingCardX > slotCardX && i > 0)
{
if (cardSlots[i - 1].isEmpty)
{
DraggableUIObject card = cardSlots[i].slotCard;
card.transform.SetParent(cardSlots[i - 1].transform);
card.SetLocalPosZero();
break;
}
}
}
}
이러면 자연스럽게 카드와 가장 가까운 슬롯은 비어있는 상태가 된다. 이제 OnEndDrag
에서 비어있는 슬롯으로 카드의 부모를 설정해주면,
private void OnEndDragCard(DraggableUIObject drag)
{
for(int i = 0; i < cardSlots.Length; i++)
{
if(cardSlots[i].isEmpty)
{
drag.transform.SetParent(cardSlots[i].transform);
break;
}
} // ToDo; for문으로 비어있는 슬롯을 찾는것보다 더 나은 방법이 있을 수도 있음.
drag.SetLocalPosZero();
}
기본적인 느낌을 흉내내볼 수 있었다.