손패에 쥐고 있는 카드중 몇 장만 골라서 바꾸고 싶은 경우가 생길 수도 있다. 그럼 손패에 어떤 카드가 선택되었는지 확인할 수 있는 기능이 필요할 것 같은데, 간단하게 카드를 클릭하면 조금 위로 올리는 기능을 만들어 보기로 했다. 비주얼은 어짜피 알아서 따라오니까, 카드 오브젝트만 클릭했을 때 로컬값을 조정해주면 될 듯?
public class Card : DraggableUIObject<Card>
{
// ~~
public bool isSelected = false;
// ~~
}
일단 카드 내부에 이게 선택되었는지 확인하기 위한 isSelected
를 추가해줬음. 그리고 포인터가 Up되는 시점에 이 값을 반대로 바꿔주면 된다.
public class CardPlayHandler : MonoBehaviour
{
// ~~
private void OnCardPointerUp(Card card)
{
//~~
card.isSelected = !card.isSelected;
}
}
이러면 끝 아님? 맞긴함. 근데 문제는 이 오브젝트가 드래그가 가능한 카드 오브젝트라는거였음. 단순히 클릭했을때 뿐만 아니라 드래그가 종료되는 시점에도 호출돼서 선택하기 싫어도 선택되는 상황이 벌어졌다. 흠 그럼 다른 방법을 써야되나.
머리에 떠오른 선택지는 두개였음.
1. 카드에 IPointerClick
인터페이스를 추가해서 셀렉 디셀렉은 여기서 따로 처리해주기.
2. 카드가 드래그된건지 그냥 클릭된건지 판별하는 방법을 추가해서 드래그된 카드라면 포인터업 시점에 isSelected
에 관여하지 않기.
사실 1번을 먼저 해봤는데, 새 인터페이스 추가하고 이벤트 연결하는 일뿐 아니라 원래 있던 포인터다운 / 포인터업 액션에서 있는 작업과 중복되는 일을 제외하는게 참으로 복잡하고 머리가 아팠다. 그래서 하다가 포기하고 2번으로 틀었음.
드래그 핸들러는 드래그 동작이 있어야 호출된다. 클릭하고 포인터로 이동해야 호출됨. 이걸 이용해서 이게 그냥 클릭 동작인지 드래그 동작이었는지를 판별해줬다.
public class DraggableUIObject<T> : MonoBehaviour, 각종 드래그 핸들러 인터페이스
{
public bool wasDragged = false;
public virtual void OnBeginDrag(PointerEventData eventData)
{
wasDragged = true;
}
public virtual void OnEndDrag(PointerEventData eventData)
{
wasDragged = false;
}
}
이러면 단순한 클릭 동작에선 wasDragged
가 false
로 유지될테고, 드래그 동작에선 wasDragged
가 true
일테니까 PointerUp
에서 wasDragged
를 체크해주면.. 엥 근데 저거 EndDrag
랑 PointerUp
중에 어느게 먼저 호출되는거에요? 진짜 모르기 때문에 테스트 해봤다. 다행히 포인터업이 먼저 호출됨. 그럼 드래그된 오브젝트는 포인터업 호출시점에서
wasDragged
가 참일테니 이 조건만 추가해주면 된다.
public class CardPlayHandler : MonoBehaviour
{
// ~~
private void OnCardPointerUp(Card card)
{
//~~
if(!wasDragged) card.isSelected = !card.isSelected;
}
}
이러면 드래그가 아닌 일반 포인터업에서만 카드셀렉트 처리가 이루어지게 된다. 근데 호출 시점이 달라질까봐 불안하면 OnEndDrag
에 코루틴으로 잠깐 기다리게 해줘도 됨.
public virtual void OnEndDrag(PointerEventData eventData)
{
StartCoroutine(FrameWait());
IEnumerator FrameWait()
{
yield return new WaitForEndOfFrame();
wasDragged = false;
}
}
이러면 드래그 종료가 된 이후로도 1프레임을 기다린 후에 wasDragged
를 변경해줘서 마음이 한결 편안하고 따듯해진다.
이제 선택처리는 해줬으니, 선택 상태에 따라 카드의 위치를 바꿔줘야된다. 카드는 부모가 변경되거나 위치가 바뀔때 카드의 내장 함수 SetLocalPosZero
를 통해 위치를 0으로 바꿔줬는데, 이걸 조금 수정해주면 될 듯.
public class Card : DraggableUIObject<Card>
{
//~~
public void SetLocalPosZero()
{
transform.localPosition = Vector3.zero;
} //원랜 이걸 쓰고 있었다.
public void ResetPosition()
{
transform.localPosition =
isSelected ? transform.up * 50 : Vector3.zero;
}
}
이러면 선택된 카드는 포지션을 리셋해줄때 약간 위쪽으로 세팅될듯. 테스트 해봤다.
생각해보니 패 구성쪽으로 올라갔을땐 이게 작동하면 안될 것 같아서 따로 처리해줬음 ㅎㅎ;
public class Card : DraggableUIObject<Card>
{
//~~
public void ResetPosition()
{
if (isPlaying) rectTransform.localPosition = Vector3.zero;
else
{
transform.localPosition =
isSelected ? transform.up * 50 : Vector3.zero;
}
}
}
의도한대로 동작했다.