Second part of tutorials on how to create Memory game.

Now add empty GameObject in the Hierarchy – right click in Hierarchy window and choose Create Empty. When object is created rename it to “GameManager”, reset its position and add new script “GameManager”.

GameManager Script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// © 2017 TheFlyingKeyboard
// theflyingkeyboard.net
public class GameManager : MonoBehaviour
{
    private GameObject _firstCard = null;
    private GameObject _secondCard = null;

    private int _cardsLeft;

    private bool _canFlip = true;

    [SerializeField]
    private float _timeBetweenFlips = 0.75f; //I think that particullar value works best, but you can adjust it as you want

    public bool canFlip
    {
        get
        {
            return _canFlip;
        }
        set
        {
            _canFlip = value;
        }
    }

    public int cardsLeft
    {
        get
        {
            return _cardsLeft;
        }
        set
        {
            _cardsLeft = value;
        }
    }

    public void AddCard(GameObject card) //This function will be called from CardController class
    {
        if (_firstCard == null) //Adds first card
        {
            _firstCard = card;
        }
        else //Adds second card and checks if both cards match
        {
            _secondCard = card;
            _canFlip = false;

            if (CheckIfMatch())
            {
                DecreaseCardCount();

                StartCoroutine(DeactivateCards());
            }
            else
            {
                StartCoroutine(FlipCards());
            }
        }
    }

    IEnumerator DeactivateCards()
    {
        yield return new WaitForSeconds(_timeBetweenFlips); //Wait so player can see flipped cards and not click to fast
        _firstCard.SetActive(false);
        _secondCard.SetActive(false);

        Reset();
    }

    IEnumerator FlipCards()
    {
        yield return new WaitForSeconds(_timeBetweenFlips); //Wait so player can see flipped cards and not click too fast
        _firstCard.GetComponent<CardController>().ChangeSide();
        _secondCard.GetComponent<CardController>().ChangeSide();

        Reset();
    }

    public void Reset()
    {
        _firstCard = null;
        _secondCard = null;

        _canFlip = true;
    }

    public void DecreaseCardCount()
    {
        _cardsLeft -= 2;

        if (_cardsLeft <= 0)
        {
            //TODO GameOver
        }
    }

    bool CheckIfMatch()
    {
        if (_firstCard.GetComponent<CardController>().cardName == _secondCard.GetComponent<CardController>().cardName)
        {
            return true;
        }
        
        return false;
    }
}

After that come back to “CardController” script and modify it so it should look like this (changes are marked with <—):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// © 2017 TheFlyingKeyboard
// theflyingkeyboard.net

public class CardController : MonoBehaviour
{
    [SerializeField]
    private string _cardName; //It will be used to check if two cards match

    private bool _isUpsideDown = false; //To know if card was flipped

    private Sprite _backSideCardSprite; //Sprite that represents back of the card

    [SerializeField]
    private Sprite _frontSideCardSprite; //Sprite that represents front of the card

    private SpriteRenderer _spriteRenderer;
    private GameManager _gameManager; //<---

    private void Start()
    {
        _spriteRenderer = GetComponent<SpriteRenderer>();
        _gameManager = FindObjectOfType<GameManager>(); //Finds GameManager<---

        _backSideCardSprite = _spriteRenderer.sprite;
    }

    public string cardName
    {
        get
        {
            return _cardName;
        }
        set
        {
            _cardName = value;
        }
    }

    private void OnMouseDown() //This function is called each time player clicks on GameObject
    {
        if (!_isUpsideDown)
        {
            _gameManager.AddCard(gameObject); //Adds this card to it<---
            ChangeSide();
        }
    }

    void ChangeSide()
    {
        if (!_isUpsideDown)
        {
            _spriteRenderer.sprite = _frontSideCardSprite;
            _isUpsideDown = true;
        }
        else
        {
            _spriteRenderer.sprite = _backSideCardSprite;
            _isUpsideDown = false;
        }
    }
}

Next step is to add another GameObject, reset its position and name it “CardSpawner”.

CardSpawner script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// © 2017 TheFlyingKeyboard 
// theflyingkeyboard.net

public class CardSpawner : MonoBehaviour
{
    [SerializeField]
    private List<GameObject> _cardsToSpawn;
    [SerializeField]
    private List<int> _cardsToSpawnCount;

    [SerializeField]
    private Transform _startPoint;

    [SerializeField]
    private int _rows = 5;

    [SerializeField]
    private int _columns = 12;

    [SerializeField]
    private float _xDistance = 1.25f;

    [SerializeField]
    private float _yDistance = 1.75;

    private GameManager _gameManager;

    // Use this for initialization
    void Start()
    {
        _gameManager = FindObjectOfType<GameManager>();
    }

    private void Update() //Objects are spawned in Update, so script execution order won't affect this scrip
    {
        Spawn();
        gameObject.SetActive(false); //After spawning objects deactivate this gameObject
    }

    void Spawn()
    {
        int cardNumber;
        int maxCards = _rows * _columns;

        if (maxCards % 2 == 0)
        {
            _cardsToSpawnCount = new List<int>();

            _gameManager.cardsLeft = maxCards;

            for (int i = 0; i < _cardsToSpawn.Count; i++)
            {
                _cardsToSpawnCount.Add(0);
            }

            for (int i = 0; i < _cardsToSpawnCount.Count; i++)
            {
                _cardsToSpawnCount[i] = Random.Range(0, (int)(maxCards / (_cardsToSpawn.Count - 1)) + 1);

                if (_cardsToSpawnCount[i] % 2 != 0)
                {
                    if (Random.Range(0, 100) < 50)
                    {
                        _cardsToSpawnCount[i]--;
                    }
                    else
                    {
                        _cardsToSpawnCount[i]++;
                    }
                }
            }

            int sum = 0;

            for (int i = 0; i < _cardsToSpawnCount.Count; i++)
            {
                sum += _cardsToSpawnCount[i];
            }

            if (sum < maxCards)
            {
                for (int i = 0; i < (int)((maxCards - sum) / 2); i++)
                {
                    _cardsToSpawnCount[Random.Range(0, _cardsToSpawn.Count - 1)] += 2; //Because it must be even
                }
            }

            bool forward = true;

            for (int i = 0; i < _rows; i++)
            {
                for (int j = 0; j < _columns; j++)
                {
                    cardNumber = Random.Range(0, _cardsToSpawnCount.Count - 1);

                    if (_cardsToSpawnCount[cardNumber] > 0)
                    {
                        Instantiate(_cardsToSpawn[cardNumber], new Vector3(_startPoint.position.x + _xDistance * j, _startPoint.position.y - _yDistance * i, _startPoint.position.z), Quaternion.Euler(0.0f, 0.0f, 0.0f));

                        _cardsToSpawnCount[cardNumber]--;
                    }
                    else
                    {
                        if (forward)
                        {
                            for (int k = 0; k < _cardsToSpawnCount.Count; k++)
                            {
                                if (_cardsToSpawnCount[k] > 0)
                                {
                                    Instantiate(_cardsToSpawn[k], new Vector3(_startPoint.position.x + _xDistance * j, _startPoint.position.y - _yDistance * i, _startPoint.position.z), Quaternion.Euler(0.0f, 0.0f, 0.0f));
                                    _cardsToSpawnCount[k]--;

                                    break;
                                }
                            }
                        }
                        else
                        {
                            for (int k = _cardsToSpawnCount.Count - 1; k >= 0; k--)
                            {
                                if (_cardsToSpawnCount[k] > 0)
                                {
                                    Instantiate(_cardsToSpawn[k], new Vector3(_startPoint.position.x + _xDistance * j, _startPoint.position.y - _yDistance * i, _startPoint.position.z), Quaternion.Euler(0.0f, 0.0f, 0.0f));
                                    _cardsToSpawnCount[k]--;

                                    break;
                                }
                            }
                        }

                        forward = !forward;
                    }
                }
            }
        }
        else
        {
            Debug.Log("Number of cards must be even!");
        }
    }
}



Now add new GameObject, rename it to “SpawnStartingPoint” and place it in (-7, 3.5, 0):

After that fill field “Start Point” of CardSpawner with this object, and field “Cards To Spawn” with prefabs from “Prefabs” folder.

CardSpawner GameObject should look like this:

Next step is creating a script to count time of play and show GameOverMenu.

Next Part Of Tutorial: Time And GameOver
Memory Game Tutorial Part 2 – GameManager
Tagged on:             

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.