Unity 1주차 미니프로젝트(1)

Sungchan Ahn(안성찬)·2024년 9월 10일

내일배움캠프

목록 보기
23/104

1주차 미니프로젝트 - 팀원 이미지 맞추기

  • 카드 뒤집어서 짝 맞추는 게임을 팀원을 나타내는 캐릭터 이미지를 넣어 팀원을 소개할 수 있는 게임으로 만드는 작은 프로젝트다. 사전캠프 때 주어진 강의의 4, 5주차 - 카드뒤집기 게임을 응용하여 만들었다.

    게임 개발이 처음이어도 쉽게 배우는 모바일 게임 개발 4, 5 주차 - 카드 뒤집기 게임 https://velog.io/@asc98/20240826-TIL

  • 이번 프로젝트의 목적은 GitHub을 이용한 협업을 경험하는 것이다. 이를 통해 GitHub 사용에 익숙해지고, GitHub을 통해 공유하는 프로젝트에서 발생할 수 있는 문제점을 해결하는 과정을 경험할 수 있다.

1. 구현하고자 하는 기능 요소

  1. 카드의 짝을 모두 맞추면(게임 클리어 시) 팀원들의 사진과 이름을 한 눈에 보여주는 UI창을 띄우는 기능 : 팀원을 소개하는 목적으로 포함하였다.

  2. 선택한 두 카드가 다르면 '실패!'라고 알림 문구를 노출하는 기능

  3. 사운드 삽입 : 배경음악, 카드 클릭 시

  4. 카드 클릭 시 카드가 뒤집어지는 모습을 연출하기

  5. 게임 시작 시 카드가 중앙에서 각 위치로 흩어져 배치되는 모습 연출하기

  6. 스테이지 해금 및 구현

2. 내가 맡은 기능

4, 5번 연출 부분을 맡아 구현하였다.

1. 카드 클릭 시 카드가 뒤집어지는 모습 연출

1) Card_Flip Animation 만들기

이미지를 가리는 Back Object를 0.1초에 걸쳐 180도 돌려주는 animation을 만든다.

[그림1] Card Prefab과 Card Animations

2) Card Animator 설정

Card Animator에서 bool Parameter "isOpen"을 추가하여 isOpen값이 true가 될 때 기본 상태의 Card_Idle animation에서 Card_Flip으로 넘어가는 Transition과 isOpen값이 false가 될 때 Card_Flip에서 Card_Idle로 넘어가는 Transition을 만든다.

[그림2] Card Animator

3) Card Script에서 Animation을 적용
OpenCard()에서 "isOpen"값을 true로 바꾸면 Card_Flip Animation이 실행되고, animation이 동작하는 시간만큼 Card의 Front를 켜주고 Back을 끄는 것을 늦춘다.
(OpenCard()는 Back - Text의 Button Component에서 버튼 클릭 시 동작하는 함수로 Image가 저장된 Front 오브젝트를 켜고, Image를 가리는 Back 오브젝트를 끈다.)

public class Card : MonoBehaviour
{
	public Animator anim;
	void OpenCard()
	{
		anim.SetBool("isOpen", true);
    	Invoke("OpenCardInvoke", 0.1f);
	}
	void OpenCardInvoke()
	{
		front.SetActive(true);
		back.SetActive(false);
	}
}

2. 게임 시작 시 카드가 중앙에서 각 위치로 흩어져 배치되는 모습 연출

스크립트로 카드 위치를 제어하였다. 중앙에서 생성되어 각각 정해진 위치로 이동하는 방식이다.

  • Board Script : 카드 생성 제어
public class Board : MonoBehaviour
{
    public GameObject card;

    [HideInInspector]
    public bool isCardDistributed;

    Dictionary<GameObject, Vector2> cardList = new Dictionary<GameObject, Vector2>();

    void Start()
    {
        isCardDistributed = false;
        GenerateCard();
    }

    void Update()
    {
        if (isCardDistributed == false)
        {
            StartCoroutine(DistributeCard(0.05f));
        }
    }

    public void GenerateCard()
    {
        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);
            go.transform.position = new Vector2(0f, -0.91f);

            float x = (i / 4) * 1.4f - 2.1f;
            float y = (i % 4) * 1.4f - 3.0f;

            Vector2 targetPosition = new Vector2(x, y);
            cardList.Add(go, targetPosition);

            go.GetComponent<Card>().Setting(arr[i]);
        }
        GameManager.Instance.cardCount = arr.Length;
    }

    IEnumerator DistributeCard(float waitSeconds)
    {
        yield return new WaitForSeconds(0.5f);
        foreach (KeyValuePair<GameObject, Vector2> card in cardList)
        {
            GameObject generatedCard = card.Key;
            Vector2 cardTargetPosition = card.Value;
            generatedCard.transform.position = Vector2.Lerp(generatedCard.transform.position,
                                                            cardTargetPosition,
                                                            Time.deltaTime * 5f);
            yield return new WaitForSeconds(waitSeconds);
        }
        yield return new WaitForSeconds(0.7f);
        isCardDistributed = true;
    }
}

  1. GenerateCard()에서 카드를 16개 생성하고 각각의 card와 최종 위치를 cardList에 저장한다.

Dictionary<TKey,TValue> 클래스 : 키(key) 및 값(value)의 컬렉션

Dictionary<GameObject, Vector2> cardList = new Dictionary<GameObject, Vector2>(); 
cardList.Add(go, targetPosition);

생성된 Card(key)와 그 Card의 최종 위치(value)를 담아둔 컬렉션 cardList

  1. 16개의 카드를 Lerp 함수를 이용하여 각각 목표 위치까지 이동시키는 반복의 사이에 카드가 완전히 배치될 때까지의 시간이 필요하기 때문에 코루틴을 사용하였다.

카드의 이동은 선형보간함수 Vector2.Lerp를 이용하였다.

public static Vector2 Lerp(Vector2 a, Vector2 b, float t);
// t : 0 ~ 1
// t가 0일 때 : a를 반환
// t가 1일 때 : b를 반환
// t가 0.5일 때 : a와 b의 중간점에 있는 값을 반환
// t가 작을 수록 a에서 b로 천천히 이동한다.
  1. isCardDistributed는 마지막 카드가 목표 위치에 멈출 때까지 시간을 보낸 후에 true로 바꿔준다.

  2. 카드가 배치되는 동안 시간을 멈추기 위해서 GameManager의 Update에서 Board의 isCardDistributed가 true일 때만 시간이 더해지게 만들었다.

public class GameManager : MonoBehaviour
{
    public Board thisBoard;
    void Update()
    {
        if (thisBoard.isCardDistributed == true)
        {
            time += Time.deltaTime;
        }
    }    
}
profile
게임 개발 기록

0개의 댓글