본문 바로가기

UNITY

UNITY_20230810[팀 프로젝트_3]

카드 뒤집기 게임 제작을 마무리하고, 시연영상 촬영 및 제출을 완료했다.

게임에서 구현한 2개의 기능과 GitHub Desktop프로그램의 활용에 대해 기록한다.


  • 게임이 시작 초기에 모든 카드가 배치되는 애니메이션이 끝나기 전에 카드 클릭 이벤트를 발생시키지 않게 하는 방어 코드
  • 뒤집힌 두 카드의 일치여부를 확인하고 사라지는(다시 앞면으로 돌아가는) 동작이 수행 될 때 동안, 다른 카드에서 클릭 이벤트를 발생시키지 않게 하는 방어 코드

게임이 시작 초기에 모든 카드가 배치되는 애니메이션이 끝나기 전에 카드 클릭 이벤트를 발생시키지 않게 하는 방어 코드

 

+ 코루틴(Coroutine)함수를 사용한다.

유니티는 게임을 실행하면 모든 스크립트에 메시지 루프가 동작한다.
메시지 루프 : 유니티 내의 다양한 함수가 정해진 순서대로 실행되는 구조
특정 함수가 호출되면, 해당 함수 내의 로직을 다 수행해야만(메시지 루프를 다 소화해야만) 그 함수의 실행이 끝난다.

이와 같은 함수 특성으로 인해, 예를 들자면, A함수의 로직 수행에 5초가 소요된다고 가정할 때, 이 함수가 실행되는 5초 간 다른 로직을 실행할 수 없다. 즉, 이 5초간 게임이 멈춘다.(블로킹 현상)

이 문제를 해결하기 위해 시간이 많이 소요되는 함수와 여타 함수를 병렬로 호출, 실행하는 기능이 있는데, 이를 멀티 스레드라고 한다.

이 멀티 스레드와 유사한 기능이 유니티의 코루틴이다. (Co+Routine : 협력 동작)

코루틴의 로직과 여타 함수의 메시지 루프를 연속적으로 번갈아 가면서 수행한다고 생각하면 된다.

 

무슨 말인지 모르겠다. 당연하다. 책에 있는 내용 그대로 베꼈으니.

게임에서 구현한 코루틴을 예시로 가져온다.

아래는 그 스크립트다.

IsStartAniOff = false;

void Start()
    {
        List<GameObject> cardsArr = new List<GameObject>(); // 시작 애니메이션
        
        int[] members = new int[] { 0, 0, 1, 1, 2, 2, 3, 3 }; // 카드가 8개일 때
        
        members = members.OrderBy(item => UnityEngine.Random.Range(-1.0f, 1.0f)).ToArray();

        for (int i = 0; i < members.Length; i++)
        {
            GameObject newCard = Instantiate(card);
            cardsArr.Add(newCard);
            newCard.SetActive(false);
        }
        StartCoroutine("AppearCard", cardsArr);
    }
    
void Update()
    {
        if (IsStartAniOff == true) // 등장 애니메이션 끝났는지 확인하는 조건문
        {
            time -= Time.deltaTime;
        }
    }

IEnumerator AppearCard(List<GameObject> cardsArr)
    {
        IsStartAniOff = false;
        for (int num = 0; num < cardsArr.Count; num++)
        {
            yield return new WaitForSeconds(0.15f); //0.15초에 하나씩
            cardsArr[num].SetActive(true); //카드가 활성화
            cardsArr[num].GetComponent<Animator>().SetTrigger("IsAppear"); // 애니메이션도 동작
            if (num == cardsArr.Count-1)
            {
                yield return new WaitForSeconds(0.3f);
                IsStartAniOff = true;
            }
        }
    }

 

상당히 성의없는 코드 스크랩이다. 

cardsArr배열 변수(게임 초기에 처음 배치되는 카드 오브젝트들의 집합 배열)를 매개로 하는 AppearCard코루틴 함수를 실행한다.

AppearCard코루틴 함수가 실행되면, 배치될 카드의 갯수만큼 각 카드가 활화되고, IsAppear애니메이션이 작동하는데,

이 과정이(아래의 if문까지) 0.15초마다 하나의 카드에 일어난다.

또한(사실 여기가 본문이다.), 배치되는 카드가 전체 카드 중 마지막 카드일 경우, 0.3초 동안 게임이 정지하고 난 후에 IsStartAniOff = true, 즉 초기 애니메이션이 끝나고 update함수로 시간이 흐른다.

이 0.15초, 0.3초의 코루틴이 계속 동작하는 시간동안은 게임이 정지되어 카드 배치 애니메이션 외에는 아무것도 일어나지 않는다. 

만약 코루틴이 아니고 그냥 함수가 사용됐다면? 0.15와 같은 약간의 시간 간격 없이 바로 모든 카드가 일제히 생성되고 시간도 동시에 흐른다.


뒤집힌 두 카드의 일치여부를 확인하고 사라지는(다시 앞면으로 돌아가는) 동작이 수행 될 때 동안, 다른 카드에서 클릭 이벤트를 발생시키지 않게 하는 방어 코드

 

카드를 클릭하여 뒤집을 수 있는가? 라는 canOpen변수(bool)로 제어한다.

아래는 그 GM코드다.

public bool canOpen = true; // 카드를 뒤집을 수 있는가?의 전역 변수

public void IsMatched() // 카드가 두 장 뒤집히면 작동하는 카드 매칭 함수
    {
        canOpen = false; // 매치 판정 중일때는 다른 카드 뒤집기 불가
        
    	string firstCardImage = firstCard.transform.Find("front").GetComponent<SpriteRenderer>().sprite.name;
        string secondCardImage = secondCard.transform.Find("front").GetComponent<SpriteRenderer>().sprite.name;

            if (firstCardImage == secondCardImage)
            {
                firstCard.GetComponent<card>().DestroyCard();
                secondCard.GetComponent<card>().DestroyCard();
            }
            else
            {
                firstCard.GetComponent<card>().CloseCard();
                secondCard.GetComponent<card>().CloseCard();
            }
    } // 코드 생략

매칭 판정 중일 때는 다른 카드를 뒤집을 수 없다.

그렇다면 매칭이 끝나고 후속 동작 이후에는 카드를 다시 뒤집을 수 있어야 한다.

아래는 해당 기능을 작성한 card스크립트다.

public void DestroyCard()
    {
        Invoke("DestroyCardInvoke", 0.5f);
    }
    public void DestroyCardInvoke()
    {
        Destroy(gameObject);
        gameManager.I.canOpen = true; // 매치 판정 이후 두 카드의 동작이 진행된 후 다시 카드 뒤집기를 가능하게 원위치
    }
    public void CloseCard()
    {
        Invoke("CloseCardInvoke", 0.5f);
    }
    public void CloseCardInvoke()
    {
        // 생략 gameManager.I.countDownGO.SetActive(false);
        transform.Find("front").gameObject.SetActive(false);
        transform.Find("back").gameObject.SetActive(true);
        // 생략 transform.Find("back").gameObject.GetComponent<SpriteRenderer>().color = Color.gray;
        gameManager.I.canOpen = true; // 매치 판정 이후 두 카드의 동작이 진행된 후 다시 카드 뒤집기를 가능하게 원위치
    }

뒤집힌 두 카드가 일치할 경우 DestroyCard가 실행되고, 0.5초 후에 DestroyCardInvoke가 실행된다.

카드는 사라지고, GM의 canOpen변수는 다시 true가 되어 isMatch에서 falserk 되기를 기다린다.

두 카드가 다를 경우(CloseCard)도 거의 같다.


GitHub Desktop(깃헙 데탑) 프로그램

 

기존의 Git Bash에서의 명령어를 통한 깃헙 활용은 초심자가 하기엔 가시성도 떨어지고, 수정사항 소실의 위험도 굉장히 크다.

따라서, 고차원의 기능은 다소 간략화됐지만, 가시성과 직관성을 극대로 높인 깃헙 데탑으로 협엽을 진행한다.

아래는 깃헙 데탑의 화면이다.

빨강은 현재 진행중인 프로젝트
주황 : 브랜치, main이 주 브랜치이며, 이 탭을 통해 타 브랜치 검색과 생성, main과의 merge를 수행한다.

노랑 : commit한 브랜치의 push, push된 버전의 pull, 현재 브랜치에서의 버전으로 패치한다.

초록 : commit하기 전, 프로젝트에서 수정한 내역을 확인, 수정, 제거한다.

파랑 : 현재 브랜치에서 push된 버전의 모든 내역을 확인한다.

보라 : changes에서의 수정 내역에 주석을 추가하여 현재 브랜치에 commit한다.

 

사실 깃&깃헙 연동은 안썼다. 
진짜 들은 것 처럼 처음 프로젝트 시작할 때 딱 한번 하는 내용이기도 하고, 처음이라 좀 엉겁결에 해서 이미 잊어버렸다.

commit, merge, push, pull, fetch할 때, 꼭꼬꼬꼬고꼭ㄱ꼭 현재 브랜치가 무엇인지 확인한다. 괜히 수정 날리지 말고.


솔직히 말하겠다.

git bash강의 들을 때 졸았다. 그래서 그 내용 거의 기억 안난다.

졸았던 주제에 팀 프로젝트를 앞에 두고 막막했는데, 깃헙데탑은 "신"이었다. goat

'UNITY' 카테고리의 다른 글

UNITY_20230811[1주차 회고록]  (0) 2023.08.11
UNITY_20230811[팀 프로젝트_4]  (0) 2023.08.11
UNITY_20230809[팀 프로젝트_2]  (0) 2023.08.09
UNITY_20230808[팀 프로젝트_1]  (0) 2023.08.08
UNITY_20230802[카드 짝 맞추기]  (0) 2023.08.03