
카드를 뒤집어서 짝을 맞추는 게임
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;
}
}