8장의 카드가 두 장씩 랜덤으로 생성되는 것이 목표이다. 각 카드에 (0, 0, 1, 1, 2, 2, ~) 이렇게 번호를 메겨 이미지를 설정해주자.
// gameManager.cs
using System.Linq;
void Start()
{
int[] rtans = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7 };
// rtans 변수에 데이터를 저장해 준다.
rtans = rtans.OrderBy(item => Random.Range(-1.0f, 1.0f)).ToArray();
// 리스트의 데이터를 정렬해 주겠다 => 랜덤하게 !.리스트로 저장;
for (int i = 0; i < 16; i++)
{
GameObject newCard = Instantiate(card);
newCard.transform.parent = GameObject.Find("cards").transform;
float x = (i / 4) * 1.4f - 2.1f;
float y = (i % 4) * 1.4f - 3.0f;
newCard.transform.position = new Vector3(x, y, 0);
Debug.Log(rtans[i]); // 콘솔에 로그로 출력
}
}
리스트에 있는 데이터가 랜덤하게 실행이 된다 !
이미지를 코드로 사용하기 위해 Resources 폴더 생성 후 넣어준다.
// gameManager.cs
void Start()
{
int[] rtans = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7 };
rtans = rtans.OrderBy(item => Random.Range(-1.0f, 1.0f)).ToArray();
for (int i = 0; i < 16; i++)
{
GameObject newCard = Instantiate(card);
newCard.transform.parent = GameObject.Find("cards").transform;
float x = (i / 4) * 1.4f - 2.1f;
float y = (i % 4) * 1.4f - 3.0f;
newCard.transform.position = new Vector3(x, y, 0);
string rtanName = "rtan" + rtans[i].ToString();
// 이미지의 이름을 만들어 준다.
newCard.transform.Find("front").GetComponent<SpriteRenderer>().sprite = Resources.Load<Sprite>(rtanName);
// front를 찾아서 sprite를 Resources 폴더의 이미지로 변경해 준다.
}
}
적용이 잘되었다 !
카드가 흔들리는 듯한 효과 !
누르는 듯한 효과 !
즉시 애니메이션이 실행되게 설정
애니메이션 재생 시기를 설정 !
C# 기본 문법 공부 때 bool 형식이 자주 쓰인다고 배웠을 때 언제 쓰일까? 궁금했는데 직접 설정을 해보니 아주 강력한 문법임을 알게 되었다.
// card.cs
public Animator anim; // 만들어둔 animator을 card에 알려준다
public void openCard()
{
anim.SetBool("isOpen", true); // idle에서 flip parameters 실행
transform.Find("front").gameObject.SetActive(true); // 카드 앞면 활성화
transform.Find("back").gameObject.SetActive(false); // 카드 뒷면 비활성화
}
카드가 뒤집어 진다 !
목표는 같은 카드를 뒤집었다면 사라지게 만들고 다른 카드라면 다시 뒤집어 준다.
// gameManager.cs 싱글톤
public static gameManager I;
void Awake()
{
I = this;
}
// gameManager.cs
public GameObject firstCard;
public GameObject secondCard;
public void isMatched()
{
Debug.Log("판단하자");
}
// card.cs
public void openCard()
{
anim.SetBool("isOpen", true);
transform.Find("front").gameObject.SetActive(true);
transform.Find("back").gameObject.SetActive(false);
if (gameManager.I.firstCard == null)
{
gameManager.I.firstCard = gameObject;
}
else
{
gameManager.I.secondCard = gameObject;
gameManager.I.isMatched();
}
}
// gameManager.cs
public void isMatched()
{
string firstCardImage = firstCard.transform.Find("front").GetComponent<SpriteRenderer>().sprite.name;
string secondCardImage = secondCard.transform.Find("front").GetComponent<SpriteRenderer>().sprite.name;
// front의 이미지 이름을 불러오는 변수 저장
if (firstCardImage == secondCardImage) // 두 이미지의 이름이 같다면 !
{
Debug.Log("같다!");
}
else
{
Debug.Log("같지 않다!"); // 두 이미지의 이름이 다르다면 !
}
firstCard = null;
secondCard = null;
// 적용되었던 card를 비워준다.
}
gameManager.cs에서 첫 번째 카드와 두 번째 카드가 동일한지 판단하는 함수를 만들어 준다.
// card.cs
public void destroyCard() // gamaManager에서 사용하기 위해 public 입력
{
Invoke("destroyCardInvoke", 1.0f); // 1초 뒤에 실행
}
void destroyCardInvoke() // card에서만 작동하면 되니 public를 입력할 필요는 없다.
{
Destroy(gameObject); // 카드 삭제
}
public void closeCard()
{
Invoke("closeCardInvoke", 1.0f);
}
void closeCardInvoke() // 카드를 뒤집어주는 함수
{
anim.SetBool("isOpen", false);
transform.Find("back").gameObject.SetActive(true);
transform.Find("front").gameObject.SetActive(false);
}
card.cs에서 카드를 사라지게 만드는 함수, 둘 다 뒷면으로 뒤집어지는 함수를 만들어 준다.
// gameManager.cs
public void isMatched()
{
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();
}
firstCard = null;
secondCard = null;
}
끝났다는 텍스트를 만들어 준다.
// gameManager.cs
public GameObject endTxt; // endTxt를 gameManager에게 알려 준다.
public void isMatched()
{
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();
// 카드 두 장이 동일한지 판단할 때 !
int cardsLeft = GameObject.Find("cards").transform.childCount;
// cards 하위에 있는 항목의 개수를 불러온다.
if (cardsLeft == 2) // 항목의 개수가 2개일 때 !
{
endTxt.SetActive(true); // endTxt를 활성화
Time.timeScale = 0.0f; // 게임의 시간을 멈춘다.
}
}
else
{
firstCard.GetComponent<card>().closeCard();
secondCard.GetComponent<card>().closeCard();
}
firstCard = null;
secondCard = null;
}
// endTxt.cs
using UnityEngine.SceneManagement;
public void retryGame()
{
SceneManager.LoadScene("MainScene");
}
끝~에 button component를 추가하기 위해 script 생성 후 코드 추가
// gamaManager.cs
void start()
{
Time.timeScale = 1.0f;
}
시간을 다시 흐르게 해준다.
// gameManager.cs
void Update()
{
time += Time.deltaTime;
timeTxt.text = time.ToString("N2");
if (time > 30.0f)
{
endTxt.SetActive(true);
Time.timeScale = 0.0f;
}
}
gameManager.cs의 Update( ) 부분에 코드를 추가해주면 간단하게 완성
if (time == 30.0f)
로 처음에 적용을 했었는데 시간이 멈추지 않았다. 그래서 해설을 보고 풀었으나 딱 30이 되었을 때 왜 if가 실행되지 않았는지는 튜터님께 물어볼 예정이다.
새로운 명령어와 기능들이 가장 많이 등장했던 예제였다.. 그렇게 어려운 개념은 없었으나 반복숙달이 요건인 듯 싶다. 나중에 시간을 내어 내가 좋아하는 이미지들로 만들 예정이며, 도전 목표의 추가 기능들도 반드시 해볼 작정이다 !