Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

개임 게발

[Unity] [르탄이 카드 뒤집기] 애니메이션, 카드 뒤집기 기능, 카드 판정 시스템 만들기 본문

강의 정리

[Unity] [르탄이 카드 뒤집기] 애니메이션, 카드 뒤집기 기능, 카드 판정 시스템 만들기

lhgenol 2025. 2. 3. 22:19

카드 만들기 - 애니메이션과 뒤집기(4-5)

카드 애니메이션 만들기

  • 카드가 까딱까딱 움직이고, 카드를 클릭했을 때 살짝 작아졌다가 이미지가 뜨는 애니메이션을 만들어 보자. (+클릭시 카드 뒤집기까지)
  • Card Prefab을 꺼내와서 씬에 올려 놓고 CardIdle 애니메이션 클립 생성, 루프 체크 -> 클립을 카드 오브젝트에 드래그 드롭 -> Apply All
  • CardIdle 더블클릭 -> 10(Rotation z0) -> 20(Rotation z3) -> 40(Rotation z0)
  • 까딱까딱 애니메이션 완성
  • 다음은 카드 클릭 시 살짝 작아지는 애니메이션. 역시 카드 애니메이션 클립에서 CardIdle 우클릭 -> Create New Clip -> 'Card Flip' -> 10(Scale 1.2)
  • 이건 카드 클릭 시 한 번만 동작해야 되기 때문에 루프타임 체크 해제
  • 두 개의 애니메이션이 만들어 졌으니, 조건에 따라 둘 중 어느 애니메이션이 실행될 건지 결정해 줘야 한다.
  • Card 애니메이션 더블클릭해 컨트롤러로 들어가기 -> Parameters에서 'isOpen' bool값 생성 -> CardIdle 우클릭 -> Make Transition 우클릭해 Flip으로 하나, Flip에서 Idle로 하나 만들기
  • Idle에서 Flip으로 가는 건 isOpen이 true일 때 작동시켜주면 됨. Conditions + 눌러주고 Exip Time 체크 해제, Duration 0
  • Flip에서 Idle로 가는 건 Exip isOpen이 flase일 때 작동. Conditions + 눌러주고 false 변경 -> Time 체크 해제, Duration 0
  • 이렇게 해주면 코드에서 Setbool을 통해 그때그때 원하는 애니메이션을 실행시킬 수 있다.
  • 이제 스크립트로 가서 카드가 열리고 닫히는 기능을 만들어 보자.
  • 카드를 눌러서 어떤 기능이 실행되려면 버튼이 달려 있어야 한다. Card의 Back 밑에 Text에다가 Button 컴포넌트 추가
  • 마지막으로 Card Prefab Apply All 시켜주기

카드 뒤집기 기능 만들기

    public void OpenCard()
    {

    }
  • Card 스크립트에 OpenCard 함수를 만들어 줬다.
  • 이 OpenCard가 실행될 때 앞면(Front) 카드가 SetActive(true)가 되어야 함. 원래 켜저 있던 물음표가 달려 있는 뒷면(Back) 모양은 꺼져야 함
  • 그럼 두 개의 게임 오브젝트가 필요하고, 세 번째로는 애니메이션을 실행시켜 줘야 함
    public GameObject front;
    public GameObject back;

    public Animator anim;

    public SpriteRenderer frontImage;
  • front back 변수 추가, 애니메이션을 실행시켜 주기 위해 Animator도 가져옴
  • 기존에 SpriteRenderer front로 되어있던 건 frontImage로 수정
    public void OpenCard()
    {
        front.SetActive(true);
        back.SetActive(false);
        anim.SetBool("isOpen", true);
    }
  • OpenCard에서 front는 켜주고 back은 꺼준다.
  • 애니메이션은 SetBool 사용. 파라미터 이름은 isOpen. isOpen값을 true로 해줘야 CardFlip 애니메이션이 실행됨
    public void OpenCard()
    {
        anim.SetBool("isOpen", true);
        front.SetActive(true);
        back.SetActive(false);
    }
  • 그런데 애니메이션이 먼저 실행된 다음에 앞면이 켜지고 뒷면이 꺼져야 하니 SetActive을 맨 위로 올려줌
  • 이 로직이 제대로 작동하기 위해서 유니티로 가서 세팅을 해주자.
  • Card Prefab에 들어가서 Card 스크립트 변수에 각각 넣어준다. anim에는 Card 오브젝트 넣기. front Image는 front를 넣는다.
  • 이제 클릭했을 때 실행될 수 있게끔 만들어줘야 함. Text 컴포넌트로 가서 Button -> On Click + -> None에 Card 오브젝트 -> No Function -> Card -> OpenCard() 로직 등록
  • 플레이 해보면, 카드를 클릭했을 때 애니메이션이 동작하며 카드의 이미지가 보여진다.

카드 만들기 - 판정 시스템(4-6)

카드 판정 시스템 만들기

  • 이제 닫혀야 한다. 클릭한 두 개의 카드를 비교해서 이미지가 같다면 파괴시켜주고 같지 않다면 다시 닫아주는 판정 시스템을 만들어 보자.
  • 각각 카드에 입력된 숫자가 짝을 이루고 있기 때문에 카드 이미지를 비교하기 위해서는 이 숫자가 같으면 파괴시켜 주면 되겠다. 결국 이 카드의 숫자를 비교하면 됨
    public void Match()
    {
        Debug.Log("판단하자.");
    }
  • GameManager 스크립트에다 만들어 보자.
  • 먼저 Matched 함수와 디버그 로그를 적어줬다.
    public Card firstCard;
    public Card secondCard;
  • 그리고 필요한 변수 두 개를 작성했다.
  • 카드 2개의 정보를 가지고 있어야 하니, 그 정보를 가지고 있는 Card 스크립트 필요. Card 스크립트를 자료형으로 하는 firstCard, secondCard 작성
  • 그러면 첫 번째 카드가 열렸을 때 이 카드가 게임 매니저에 있는 firstCard에 정보를 넘겨주면 되겠다.
  • 그리고 두 번째로 열리는 카드는 firstCard라고 하는 변수에 정보가 있는지 없는지를 확인하고, 있다면 secondCard 변수에 정보를 넘겨주고 Matched라는 함수를 발동시켜주면 될 것.
  • 게임 매니저에 있는 firstCard, secondCard에 접근하기 위해서는 싱글톤을 만들어 줘야 함
    public static GameManager Instance;

    public Card firstCard;
    public Card secondCard;

    public Text timeTxt;
    float time = 0.0f;

    private void Awake()
    {
        if(Instance == null)
        {
            Instance = this;
        }
    }
  • Instance 변수와 Awake 함수 추가
    public void OpenCard()
    {
        anim.SetBool("isOpen", true);
        front.SetActive(true);
        back.SetActive(false);

          // firstCard가 비었다면,
        // firstCard에 내 정보를 넘겨준다.

        // firstCard가 비어있지 않다면,
        // secondCard에 내 정보를 넘겨준다.
        // Matched 함수를 호출해 준다.
    }
  • 그리고 Card 스크립트로 넘어가서, 이 OpenCard에서 아까 말한 전략처럼 정보를 firstCard에 넣을지 secondCard에 넣을지 결정해 주면 되겠다.
  • 위 주석의 내용을 코드로 작성해 보자.
    public void OpenCard()
    {
        anim.SetBool("isOpen", true);
        front.SetActive(true);
        back.SetActive(false);

        // firstCard가 비었다면,
        if(GameManager.Instance.firstCard == null)
        {
            // firstCard에 내 정보를 넘겨준다.
        }
  • '비어있다'는 null을 사용하면 됨
    public void OpenCard()
    {
        anim.SetBool("isOpen", true);
        front.SetActive(true);
        back.SetActive(false);

        // firstCard가 비었다면,
        if(GameManager.Instance.firstCard == null)
        {
            // firstCard에 내 정보를 넘겨준다.
            GameManager.Instance.firstCard = this;
        }
  • 내 정보를 넘겨주는 방법은?
  • firstCard의 자료형은 Card. 그런데 그게 담겨있는 클래스가 바로 Card 클래스. 그래서 나 자기 자신을 넘겨주면 되기 때문에 this라고 적어주면 됨
  • 싱글톤을 만들 때 Instance = this라고 했던 것과 같다.
    public void OpenCard()
    {
        anim.SetBool("isOpen", true);
        front.SetActive(true);
        back.SetActive(false);

        // firstCard가 비었다면,
        if(GameManager.Instance.firstCard == null)
        {
            // firstCard에 내 정보를 넘겨준다.
            GameManager.Instance.firstCard = this;
        }
        // firstCard가 비어있지 않다면,
        else
        {
            // secondCard에 내 정보를 넘겨준다.
            GameManager.Instance.secondCard = this;
            // Matched 함수를 호출해 준다.
            GameManager.Instance.Matched();
        }
    }
  • '비어있지 않다면'은 위와 이어지니 else문 사용
  • secondCard 역시 this 사용
  • 유니티로 가서 플레이 해보면, 카드 클릭 시 GameManager 창에 클릭한 카드의 정보가 들어간다.
  • 이제 이 first, second Card의 정보를 확인해서 숫자가 같지 않다면 닫아주고 같다면 파괴해주는 로직을 Matched에다가 적어보자.
    public void Matched()
    {
        Debug.Log("판단하자.");
    }
  • GameManager 스크립트로 돌아왔다.
  • 이제 이 디버그 로그 대신 firstCard에 있는 idx와 secondCard에 있는 idx를 비교해주는 코드를 적자.
public class Card : MonoBehaviour
{
    public int idx = 0;
  • 그 전에 잠깐 Card 스크립트로 가서 idx에 접근할 수 있게 int idx 변수를 public으로 만들어 줌
  • 이제 GameManager에서 idx를 꺼내올 수 있다.
    public void Matched()
    {
        if(firstCard.idx == secondCard.idx)
        {
            // 파괴해라.
        }
        else
        {
            // 닫아라.
        }
    }
  • 만약에 firstCard에 있는 idx가 같다면 파괴해라. 그렇지 않다면 닫아라.
  • 카드를 파괴하고 닫는 이 기능은 Card에다 만들어 주도록 하자.
    public void DestroyCard()
    {
        Destroy(gameObject);
    }

    public void CloseCard()
    {

    }
  • Card 스크립트로 가서 파괴(DestroyCard)와 닫는(CloseCard) 코드 작성
    public void CloseCard()
    {
        anim.SetBool("isOpen", false);
        front.SetActive(false);
        back.SetActive(true);
    }
  • 닫아주는 건 열어줬던 때와 반대로 해주면 되겠다. 애니메이션은 다시 Idle로 바꿔주고 front는 닫아주고 back은 켜준다. 해당 코드 작성
    public void Matched()
    {
        if(firstCard.idx == secondCard.idx)
        {
            // 파괴해라.
            firstCard.DestroyCard();
            secondCard.DestroyCard();
        }
        else
        {
            // 닫아라.
            firstCard.CloseCard();
            secondCard.CloseCard();
        }
    }
  • 그리고 GameManager에서 DestroyCard와 CloseCard 함수를 불러준다.
  • 유니티로 돌아가서 플레이 해보면, 클릭한 두 카드의 정보가 GameManager 창에 그대로 남아있어서 한번 클릭되면 안 바뀐다.
  • 파괴시키든 닫든 간에 기존의 firstCard, secondCard에 있는 정보들은 다시 비워줘야 한다. 이 로직까지 추가하자.
    public void Matched()
    {
        if(firstCard.idx == secondCard.idx)
        {
            // 파괴해라.
            firstCard.DestroyCard();
            secondCard.DestroyCard();
        }
        else
        {
            // 닫아라.
            firstCard.CloseCard();
            secondCard.CloseCard();
        }

        firstCard = null;
        secondCard = null;
    }
  • 뭐가 됐든 일단 정보들은 비워준다(null).
  • 다시 플레이 해보면, 이미지가 같을 때 파괴되고 정보들도 null되는 걸 볼 수 있다.
  • 문제는 확인할 겨를도 없이 바로 파괴돼버린다. 두 번째 카드는 시간차를 두고 닫거나 파괴해 주자.
  • 딜레이 필요. 딜레이는 Invoke를 통해 구현해 보자.
    public void DestroyCard()
    {
        Destroy(gameObject);
    }

    void DestroyCardInvoke()
    {

    }
  • Card 스크립트에 DestroyCardInvoke 함수 작성
  • 안에는 위에 있는 로직을 그대로 가져와 보자.
    public void DestroyCard()
    {
        Invoke("DestroyCardInvoke", 1.0f);
    }

    void DestroyCardInvoke()
    {
        Destroy(gameObject);
    }
  • Destroy(gameObject);를 DestroyCardInvoke에 옮겨주고, DestroyCard에는 Invoke를 실행해 주자. 딜레이는 1초.
    public void CloseCard()
    {
        Invoke("CloseCardInvoke", 1.0f);
    }

    void CloseCardInvoke()
    {
        anim.SetBool("isOpen", false);
        front.SetActive(false);
        back.SetActive(true);  
    }
  • Close도 똑같이 작성해 준다.
  • 플레이 해보면, 딜레이가 반영돼 두 개의 카드 이미지를 확인하고서 닫히거나 파괴된다.