20240826 TIL

Sungchan Ahn(안성찬)·2024년 8월 26일

내일배움캠프

목록 보기
18/104
post-thumbnail

모바일 게임개발 4, 5주차 강의. [르탄이 카드 뒤집기 게임]

카드를 뒤집어서 짝을 맞추는 게임

[Image1, 2, 3] 왼쪽부터 StartScene, 게임 진행 화면, 게임 종료 화면

  • StartScene

    • AudioManager
      게임 배경음악을 담당하는 오브젝트. StartScene과 MainScene에 모두 있어서 스크립트에서 AudioManager를 싱글톤화하고 DontDestroyOnLoad(gameObject)을 이용해 StartScene에서 시작된 배경음악이 MainScene으로 넘어가도 유지되게 하였다.

      public class AudioManager : MonoBehaviour
      {
        public static AudioManager Instance;
      
        AudioSource audioSource;
        public AudioClip clip;
      
        private void Awake()
        {
            if(Instance == null)
            {
                Instance = this;
                DontDestroyOnLoad(gameObject);
            }
            else
            {
                Destroy(gameObject);
            }
        }
      
        void Start()
        {
            audioSource = GetComponent<AudioSource>();
      
            audioSource.clip = this.clip;
            audioSource.Play();
        }
      }
  • MainScene

    • Board
      카드 생성 위치, 카드 이미지 랜덤 배치를 담당하는 오브젝트. 이 오브젝트 내에 카드 prefab이 생성된다.

      카드배치
      12 (0, 3)13 (1, 3)14 (2, 3)15 (3, 3)
      8 (0, 2)9 (1, 2)10 (2, 2)11 (3, 2)
      4 (0, 1)5 (1, 1)6 (2, 1)7 (3, 1)
      0 (0, 0)1 (1, 0)2 (2, 0)3 (3, 0)

      카드간의 거리는 1.4f, 0번째 카드 위치는 (-2.1f, -3.0f)
      [i]번째 카드의 x좌표는 i를 4로 나눴을 때 나머지: i % 4
      [i]번째 카드의 y좌표는 i를 4로 나눴을 때 몫: i / 4

      이미지 랜덤 배치
      Orderby(): 비교연산자를 이용하여 오름차순으로 정렬. 여기서는 Random.Range에서 나오는 숫자와 비교하여 정렬하기 때문에 랜덤으로 정렬한다.

      public class Board : MonoBehaviour
      {
        public GameObject card;
      
        void Start()
        {
            int[] arr = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7 };
            arr = arr.OrderBy(x => Random.Range(0f, 7f)).ToArray();
      
            for (int i = 0; i < 16; i++)
            {
                GameObject go = Instantiate(card, this.transform);
      
                float x = (i % 4) * 1.4f - 2.1f;
                float y = (i / 4) * 1.4f - 3.0f; 
      
                go.transform.position = new Vector2(x, y);
                go.GetComponent<Card>().Setting(arr[i]);
            }
      
            GameManager.Instance.cardCount = arr.Length;
        }
      }
      
    • Card

      Setting(int number) : Board에서 호출. 매개변수 int number에 arr[i]를 받아와서 idx변수(int idx : 카드 인덱스. 이미지 8개 0 ~ 7)에 저장. 카드 오브젝트의 Sprite에 각 인덱스에 해당하는 이미지를 받아온다.

      OpenCard() : 카드 오브젝트 클릭 시 가리는 오브젝트를 끄고 이미지를 보여준다. 사운드와 애니메이션도 적용한다. 첫 번째로 누른 카드를 GameManager의 firstCard에 넣고, 두 번째 카드를 누르면 secondCard에 넣고 Matched()를 호출한다.

      DestroyCard() : 카드 오브젝트 제거

      CloseCard() : 카드를 다시 가림

      public class Card : MonoBehaviour
      {
        public GameObject front;
        public GameObject back;
      
        public Animator anim;
      
        public SpriteRenderer frontImage;
      
        AudioSource audioSource;
        public AudioClip clip;
      
        public int idx = 0;
      
        void Start()
        {
            audioSource = GetComponent<AudioSource>();
        }
        public void Setting(int number)
        {
            idx = number;
            frontImage.sprite = Resources.Load<Sprite>($"rtan{idx}");
        }
      
        public void OpenCard()
        {
            if (GameManager.Instance.secondCard != null) return;
      
            audioSource.PlayOneShot(clip);
            anim.SetBool("isOpen", true);
            front.SetActive(true);
            back.SetActive(false);
      
            if (GameManager.Instance.firstCard == null)
            {
                GameManager.Instance.firstCard = this;
            }
            else
            {
                GameManager.Instance.secondCard = this;
                GameManager.Instance.Matched();
            }
        }
      
        public void DestroyCard()
        {
            Invoke("DestroyCardInvoke", 1.0f);
        }
      
        void DestroyCardInvoke()
        {
            Destroy(gameObject);
        }
      
        public void CloseCard()
        {
            Invoke("CloseCardInvoke", 1.0f);
        }
      
        void CloseCardInvoke()
        {
            anim.SetBool("isOpen", false);
            front.SetActive(false);
            back.SetActive(true);
        }
      }
    • GameManager

      Matched() : Card.OpenCard()에서 받아온 firstCard와 secondCard의 인덱스를 비교해서 같으면 DestroyCard를 호출, 다르면 CloseCard를 호출하고 firstCard와 secondCard를 비운다. 짝이 맞았을때 해당하는 오디오클립을 한번 실행한다.

      EndGame() : 게임 종료. 시간이 30초를 넘거나 모든 카드가 지워지면 호출된다.

      Public int cardCount : Board에서 array의 길이(카드 개수)를 저장한다. Matched()에서 카드가 짝이 맞을때마다 줄어들어 0이되면 EndGame을 호출한다.

      public class GameManager : MonoBehaviour
      {
         public static GameManager Instance;
         public GameObject endTxt;
         
         public Card firstCard;
         public Card secondCard;
         
         public Text timeTxt;
      
         AudioSource audioSource;
         public AudioClip clip;
      
         public int cardCount = 0;
         float time = 0.0f;
      
         private void Awake()
         {
             if (Instance == null)
             {
                 Instance = this;
             }
         }
      
         void Start()
         {
             Time.timeScale = 1.0f;
             audioSource = GetComponent<AudioSource>();
         }
      
         void Update()
         {
             time += Time.deltaTime;
             timeTxt.text = time.ToString("N2");
             if (time > 30.0f)
             {
                 EndGame();
             }
         }
      
         public void Matched()
         {
             if (firstCard.idx == secondCard.idx)
             {
                 audioSource.PlayOneShot(clip);
                 firstCard.DestroyCard();
                 secondCard.DestroyCard();
                 cardCount -= 2;
                 if (cardCount == 0)
                 {
                     EndGame();
                 }
             }
             else
             {
                 firstCard.CloseCard();
                 secondCard.CloseCard();
             }
             firstCard = null;
             secondCard = null;
         }
      
         void EndGame()
         {
             endTxt.SetActive(true);
             Time.timeScale = 0.0f;
         }
      }
profile
게임 개발 기록

0개의 댓글