카드 애니메이션 만들기 2

Tom·2024년 12월 25일
0

카드게임 만들기

목록 보기
7/13

일단 우선적으로 해야 할 일은 비주얼의 계층구조를 손봐주는것이었다. 카드 오브젝트가 드래그 될 때 맨 앞으로 보내기 위해 부모를 바꿔주는 코드를 제거했고, 슬롯 카드들의 위치를 드래그중인 카드의 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;
    }
    //~~~
}

이러면 메서드의 등록 순서와 별개로 내가 원하는 액션을 먼저 실행시킬 수 있다. 아주 간편한 부분이구요.
이제야 웃네

profile
여기 글은 보통 틀린 경우가 많음

0개의 댓글

관련 채용 정보