일단 우선적으로 해야 할 일은 비주얼의 계층구조를 손봐주는것이었다. 카드 오브젝트가 드래그 될 때 맨 앞으로 보내기 위해 부모를 바꿔주는 코드를 제거했고, 슬롯 카드들의 위치를 드래그중인 카드의 x값에 따라 변경하는 코드에도 약간의 수정이 필요했음.
[SerializeField] CardSlot currentSlot;
[SerializeField] int currentSlotIndex;
private void BeginDragCard(Card card)
{
currentSlot = card.GetComponentInParent<CardSlot>();
currentSlotIndex = cardSlots.IndexOf(currentSlot);
}
private void OnDragCard(Card card)
{
float cardX = card.transform.position.x;
for (int i = currentSlotIndex - 1; i >= 0; i--)
{
if (cardX < cardSlots[i].slotCard.transform.position.x)
{
SwapSlot(currentSlot, cardSlots[i]);
currentSlot = cardSlots[i];
currentSlotIndex = i;
}
}
for (int i = currentSlotIndex + 1; i < cardSlots.Count; i++)
{
if (cardX > cardSlots[i].slotCard.transform.position.x)
{
SwapSlot(currentSlot, cardSlots[i]);
currentSlot = cardSlots[i];
currentSlotIndex = i;
}
}
}
private void SwapSlot(CardSlot from, CardSlot to)
{
Card fromCard = from.slotCard;
Card toCard = to.slotCard;
toCard.transform.SetParent(from.transform);
fromCard.transform.SetParent(to.transform);
toCard.SetLocalPosZero();
}
그리고 카드비주얼에서는 포인터를 떼는시점에 현재 슬롯의 인덱스를 받아와서 카드의 인덱스를 설정해주기로 했다.
private void OnPointerUp(Card card)
{
transform.SetSiblingIndex(card.transform.parent.GetSiblingIndex());
}
카드가 자기 자리를 잘 찾아갔음. 그런데 역시 히드라답게 또다른 문제가 발생하였으니
무수히 많은 버그의 악수 요청이...
어떤 동작에서 문제가 생기는지 확인해보니 카드를 내려놓을 때 생기고 있었다. OnPointerUp
에서 실행되는 메서드들에 문제가 있는 것 같다고 판단되었음. 아마 원래는 카드의 부모가 원래 슬롯 -> 드래그 슬롯 -> 이동하려는 슬롯
의 순서로 바뀌었는데, 이 작업이 필요없어서 바로 부모를 옮겨주게 되어서 카드를 내려놓을 때 실행되는 코드가 꼬인 것 같았다. 각각 포인터를 뗄 때 무슨 일이 생기는지 그새 까먹었으니, 내가 무슨 메서드들을 더해줬는지 쭉 확인하고 고쳐줬다.
using System;
using UnityEngine;
public class CardPlayHandler : MonoBehaviour
{
//포인터 다운과 업으로 나눠서 관리했다.
private void OnCardPointerDown(Card card)
{
if (card.isPlaying)
{
card.transform.SetParent(dragTransform, true);
playCardGroup.RemoveCard(card);
}
}
private void OnCardPointerUp(Card card)
{
if (playCardGroup.isPointerOnSlot && playCardGroup.cardList.Count < 5)
{
handCardGroup.RemoveCard(card);
playCardGroup.AddCard(card);
}
else
{
handCardGroup.AddCard(card);
}
card.SetLocalPosZero();
}
}
또 너야 계층구조
비주얼의 계층구조에서 발견한 문제점은 총 두개인데,
1. 카드 비주얼에서 SetSiblingIndex
로 카드의 계층을 정해주고 있었는데, 카드 비주얼의 부모는 한개이다보니 손 패에 카드가 순서대로 잘 정렬되어있다 -> 카드가 패 구성쪽으로 이동해서 인덱스가 0이 되었다 -> 손패에 0번 카드의 인덱스가 하나 뒤로 밀렸다
의 과정을 거쳐 PlayCardGroup
에서 5장의 카드를 올렸다가 꺼내오면 손패의 0번 카드의 인덱스가 5번이 되어 뒤쪽 카드들을 가렸다.
2. 또, 카드 비주얼의 계층은 카드가 슬롯을 결정하고 난 이후에 결정되어야 하는데, 카드 비주얼의 OnPointerUp
은 카드가 생성될 때 카드의 Action
에 추가되기 때문에 나중에 실행하기 어렵다는 문제가 있었다.
이건 이제 카드 매니저에 때려 박아넣은 카드 비주얼 관리를 분리해야될 시점이 와버린것을 의미. 으악 오지 않기를 바랐건만.
using System.Collections.Generic;
using UnityEngine;
public class CardVisualHandler : MonoBehaviour
{
[SerializeField] private GameObject cardVisualPrefab;
[SerializeField] private Transform handVisualTransform;
[SerializeField] private Transform playVisualTransform;
[SerializeField] private List<CardVisual> cardVisuals;
[SerializeField] private List<CardVisual> offVisuals;
[SerializeField] private Dictionary<Card, CardVisual> cardPair = new Dictionary<Card, CardVisual>();
private void Awake()
{
for (int i = 0; i < 10; i++)
{
CardVisual initVisual = Instantiate(cardVisualPrefab, handVisualTransform).GetComponent<CardVisual>();
initVisual.gameObject.SetActive(false);
offVisuals.Add(initVisual);
}
}
public void GetCardVisual(CardData cardData, Card card)
{
CardVisual cardVisual;
if (offVisuals.Count > 0)
{
cardVisual = offVisuals[0];
offVisuals.Remove(cardVisual);
cardVisual.gameObject.SetActive(true);
}
else
{
cardVisual = Instantiate(cardVisualPrefab, handVisualTransform).GetComponent<CardVisual>();
}
cardVisual.Initialize(cardData, card);
if(!cardPair.ContainsKey(card))
{
cardPair[card] = cardVisual;
}
card.secondPointerUpAction += OnPointerUp;
}
private void OnPointerUp(Card card)
{
if (cardPair.TryGetValue(card, out CardVisual visual))
{
if (card.isPlaying)
{
visual.transform.SetParent(playVisualTransform, false);
}
else
{
visual.transform.SetParent(handVisualTransform, false);
}
visual.transform.SetSiblingIndex(card.transform.parent.GetSiblingIndex());
}
}
}
그래서 만들었다 비주얼 핸들러. 간단한 풀링기능과 부모 설정등의 기능만 만들었음.
PointerUpAction
에서 먼저 실행되야 할 코드와 나중에 실행되야 할 코드가 있는 문제는 Action
에 어떤 메서드를 먼저 더해주느냐에 따라 해결 할 수 있다. 근데 카드 비주얼의 메서드는 생성되는 시점에서 추가되어야 하니, 이를 제어하는데 어려움이 있었음. 그래서 두개로 나눠버렸다.
public class DraggableUIObject<T> : MonoBehaviour //~~ 여러 인터페이스들
{
//~~
public Action<T> firstPointerUpAction;
public Action<T> secondPointerUpAction;
//~~
public void OnPointerUp(PointerEventData eventData)
{
firstPointerUpAction?.Invoke((T)this);
secondPointerUpAction?.Invoke((T)this);
image.raycastTarget = true;
canvasGroup.blocksRaycasts = true;
}
//~~~
}
이러면 메서드의 등록 순서와 별개로 내가 원하는 액션을 먼저 실행시킬 수 있다. 아주 간편한 부분이구요.
이제야 웃네