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 and released under MIT License
// 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 and released under MIT License
// 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();
        }
    }

    public 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 and released under MIT License
// 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:             

2 thoughts on “Memory Game Tutorial Part 2 – GameManager

  • July 24, 2018 at 3:15 am
    Permalink

    Assets/GameManager.cs(67,51): error CS0122: `CardController.ChangeSide()’ is inaccessible due to its protection level

    Reply
    • July 24, 2018 at 5:16 am
      Permalink

      Fixed, there was “public” access specifier missing 🙂

      Reply

Leave a Reply

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

This website stores some user agent data. These data are used to provide a more personalized experience and to track your whereabouts around our website in compliance with the European General Data Protection Regulation. If you decide to opt-out of any future tracking, a cookie will be set up in your browser to remember this choice for one year. I Agree, Deny
504

By continuing to use the site, you agree to the use of cookies. You can read more about it the Cookies&Privacy Policy Section Above. more information

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this. You can read more about it the Cookies&Privacy Policy Section.

Close