상세 컨텐츠

본문 제목

0828 TIL - 르탄이 찾기 카드게임 만들기

스파르타 코딩캠프/'24 Today I Learned

by lucar 2024. 8. 28. 18:24

본문

벌써 4번째 게임이다. 비슷한 부분은 모두 스킵하고 핵심만 콕콕 배워보자

빠르게 빠르게 기본적인 백그라운드 및 설정을 완료해준다

 

카드 디자인을 한 후 카드 프리팹을 만들어서 프리팹 폴더에 넣어주고

 

게임매니저 빈 Hierarchy와 스크립트를 제작해서 시간이 흐를 수 있게 코드를 작성하자

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class GameManager : MonoBehaviour
{
    public Text timeTxt;

    float time = 0.0f;

    // Start is called before the first frame update
    void Start()
    {
    }

    // Update is called once per frame
    void Update()
    {

        time += Time.deltaTime;
        timeTxt.text = time.ToString("N2");
    }
}

 

이제 코드를 통해 카드를 배치해보자.

보드 스크립트를 제작하고 수정하자.

4*4로 배치한다고 했을 때

 

이런 배치 좌표를 가지게 되는데 잘 보면 X값은 4*4배치에서 4로 나눈 나머지 값이고 Y값은 4로 나눈 몫이라고 볼 수 있다.

이걸 코드로 작성해보면

void Start()
{
    for (int i = 0; i < 16; i++) //i가 16보다 작다면 반복, 반복 종료 시 i에 1을 더함
    {
        GameObject go = Instantiate(card, this.transform); //카드 오브젝트를 Board 밑으로 생성

        float x = (i % 4) * 1.4f - 2.1f; //x좌표 4로 나눈 나머지값
        float y = (i / 4) * 1.4f - 3.0f; //y좌표 4로 나눈 몫

        go.transform.position = new Vector2(x, y); //x,y값에 생성
    }
}

이렇게 나타낼 수 있다.

실행해보면?

 

깔끔하게 생성되었다.

 

지금은 각 카드에 하나의 이미지 밖에 없기 때문에 다양한 이미지를 가진 카드를 섞어서 실행할 때 마다 바뀌게 제작해보자.

우선 카드 스크립트를 작성하자.

public void Setting(int number)
{
    idx = number;
}

0 ~ 7까지 같은 숫자를 2번 반복하는 배열을 만들면 같은 숫자가 2개씩 있는 16개의 배열이 만들어진다

넘버를 입력받으면 해당하는 그림으로 바뀔 수 있도록 카드에 속성을 추가해주었다.

 

보드 스크립트도 수정해주자.

public class Board : MonoBehaviour
{
    public GameObject card;


    // Start is called before the first frame update
    void Start()
    {
        int[] arr = {0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7}; //배열로 16개의 값을 추가
        arr = arr.OrderBy(x => Random.Range(0f, 7f)).ToArray(); //배열을 랜덤한 값으로 재배열함

        for (int i = 0; i < 16; i++) //i가 16보다 작다면 반복, 반복 종료 시 i에 1을 더함
        {
            GameObject go = Instantiate(card, this.transform); //카드 오브젝트를 Board 밑으로 생성

            float x = (i % 4) * 1.4f - 2.1f; //x좌표 4로 나눈 나머지값
            float y = (i / 4) * 1.4f - 3.0f; //y좌표 4로 나눈 몫

            go.transform.position = new Vector2(x, y); //x,y값에 생성
            go.GetComponent<Card>().Setting(arr[i]); //Card 컴포넌트 안의 Setting 함수에 arr[i]의 값을 입력
        }
    }

배열로 같은 숫자를 2개씩  8개의 조합으로 총 16개의 배열을 만들었다. 숫자가 같으면 같은 그림이 나오게 할 것이다.

 

이미지 폴더에서 리소스 폴더를 새로 만들어서 내용물을 전부 옮겨주고 리소스폴더 기능을 이용해서 작성해보자.

public class Card : MonoBehaviour
{
    int idx = 0;
    public SpriteRenderer front;

    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        
    }

    public void Setting(int number)
    {
        idx = number;
        front.sprite = Resources.Load<Sprite>($"rtan{idx}"); //$표시를 통해 문자열 내부에 변수 삽입 가능
    }
}

카드가 흔들거리는 애니메이션과 눌렀을 때 뒤집어지는 애니메이션을 추가해주자.

두 가지 애니메이션을 만들고 각각 트랜지션으로 연결 해 준 후 컨디션에 isOpen이라는 bool값을 추가해주었다.

텍스트에 버튼 컴포넌트를 추가해 누르면 뒤집어 질 수 있도록 만들어보자.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Card : MonoBehaviour
{
    int idx = 0;

    public GameObject front;
    public GameObject back;

    public Animator anim;

    public SpriteRenderer frontImage;

    public void OpenCard()
    {
        anim.SetBool("isOpen", true);
        front.SetActive(true);
        back.SetActive(false);
    }
}

 

앞면과 뒷면 오브젝트를 불러오고 애니메이터에 접근할 수 있게 anim 변수를 선언해 주었다.

OpenCard라는 함수를 만들어서 버튼에 연동시켜 누를 시 실행될 수 있도록 만들어주자.

 

이제 실행해보면?

잘 작동한다.

이제 틀린 그림을 골랐을 경우 다시 뒤집어지게 만들어보자.

 

우선 카드 스크립트를 수정해보자.

public void DestroyCard() //카드가 맞다면 파괴하는 함수
{

    Invoke("DestroyCardInvoke", 1.0f);
}

public void DestroyCardInvoke()
{
    Destroy(gameObject);
}

public void CloseCard() //카드가 틀리다면 다시 뒤집는 함수
{
    Invoke("CloseCardInvoke", 1.0f);
}

public void CloseCardInvoke()
{
    anim.SetBool("isOpen", false);
    front.SetActive(false);
    back.SetActive(true);
}

Invoke를 하지 않으면 뒷 카드가 보이지도 않게 된다. 추가해주자

 

게임매니저 스크립트로 가서

public void Matched() //카드가 일치하는지 확인 하는 함수
{
    if (firstCard.idx == secondCard.idx) //카드가 같다면
    {
        firstCard.DestroyCard();
        secondCard.DestroyCard();
    }
    else //카드가 틀리다면
    {
        firstCard.CloseCard();
        secondCard.CloseCard();
    }

    firstCard = null; //오브젝트 값 초기화
    secondCard = null;
}

싱글톤 선언 후 함수를 추가로 만들어 주었다. 실행해보면?

처참한 순간기억력

그래도 잘 작동되는것 같아보인다.

 

마지막으로 엔드패널을 추가해 게임을 종료해보자.

게임 종료 시 출력 될 텍스트 UI를 추가한 후 잠시 꺼주자

 

게임매니저 스크립트에서 public int cardCount = 0;이라는 변수를 추가해준다.

보드 스크립트로 들어가서

 void Start()
 {
     int[] arr = {0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7}; //배열로 16개의 값을 추가
     arr = arr.OrderBy(x => Random.Range(0f, 7f)).ToArray(); //배열을 랜덤한 값으로 재배열함

     for (int i = 0; i < 16; i++) //i가 16보다 작다면 반복, 반복 종료 시 i에 1을 더함
     {
         GameObject go = Instantiate(card, this.transform); //카드 오브젝트를 Board 밑으로 생성

         float x = (i % 4) * 1.4f - 2.1f; //x좌표 4로 나눈 나머지값
         float y = (i / 4) * 1.4f - 3.0f; //y좌표 4로 나눈 몫

         go.transform.position = new Vector2(x, y); //x,y값에 생성
         go.GetComponent<Card>().Setting(arr[i]); //Card 컴포넌트 안의 Setting 함수에 arr[i]의 값을 입력
     }
     GameManager.Instance.cardCount = arr.Length; //카드카운트에 배열의 길이(16)을 추가
 }

카드카운터에 arr.Length값을 입력해주고

다시 게임매니저로 돌아가 스크립트를 작성하자

public void Matched() //카드가 일치하는지 확인 하는 함수
{
    if (firstCard.idx == secondCard.idx) //카드가 같다면
    {
        firstCard.DestroyCard();
        secondCard.DestroyCard();
        cardCount -= 2;
        GameOver();
    }
    else //카드가 틀리다면
    {
        firstCard.CloseCard();
        secondCard.CloseCard();
    }

    firstCard = null; //오브젝트 값 초기화
    secondCard = null;
}

void GameOver()
{
    if(cardCount == 0)
    {
        endTxt.gameObject.SetActive(true);
        Time.timeScale = 0.0f;
    }
}

카드가 같다면 카드 카운트를 줄이고 카드 카운트가 0이라면 게임오버 함수를 불러오게 설계했다.

실행해보면?

잘 작동한다.

이제 끝 텍스트를 누르면 다시 실행하게 하고 마쳐보자.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class RetryBtn : MonoBehaviour
{
    public void Retry()
    {
        SceneManager.LoadScene("MainScene");
    }
}

 

까지 진행해서 오늘의 TIL은 마무리~

관련글 더보기