Third part of tutorials on how to create Memory game.

Add new text and name it “TimeCounter”, after set Canvas and “TimeCounter” properties to the following:

Canvas propeties:

“TimeCounter” properties:

After adjusting that GameObjects add new script “TimeCounter” to “TimeCounter” GameObject.

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

// © 2017 TheFlyingKeyboard 
// theflyingkeyboard.net

public class TimeCounter : MonoBehaviour
{
    private float _timeCounter = 0.0f;

    [SerializeField]
    private Text _timeText;

    private int _counter = 1;

    private bool _countTime = true;

    public bool countTime
    {
        get
        {
            return _countTime;
        }
        set
        {
            _countTime = value;
        }
    }

    public int timeCounted
    {
        get
        {
            return _counter;
        }
    }

    // Update is called once per frame
    void Update()
    {
        if (_countTime)
        {
            if (_timeCounter >= _counter) //Updating Text each frame would be very CPU expensive
            {
                _timeText.text = "Time: " + _counter;

                _counter++;
            }

            _timeCounter += Time.deltaTime;
        }
    }
}

Fill “TimeText” field with “TimeCounter” GameObject from Canvas and create new empty GameObject in canvas (Right Click on Canvas and then choose Create Empty), set its properties to match the following ones:

After that add new Button, Image and Text to this object with properties as shown below:

The color is: #B2B2B259

Now add new script “Restart” to “RestartButton”:

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

// © 2017 TheFlyingKeyboard 
// theflyingkeyboard.net
public class Restart : MonoBehaviour {
    public void RestartGame()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().name);
    }
}

After that click little “+” in On Click () in button and drag “RestartButton” into a little field with small circle sign and choose “RestartGame” function from little menu. Finally it should be like this:

It is important to have GameObject in the following order, because Image that was created will hover “TimeCounter” and not “RestartButton” and “ScoreText”. Next step is to create new GameObject called ScoreManager with new script “ScoreManager”:

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

// © 2017 TheFlyingKeyboard 
// theflyingkeyboard.net

public class ScoreManager : MonoBehaviour
{
    private int _score = 0;

    [SerializeField]
    private int _initialTimeScoreBonus = 100000;
    [SerializeField]
    private int _bonusScorePerSecondLost = 80;
    [SerializeField]
    private int _scorePerCard = 50;

    private TimeCounter _timeCounter;

    public int score
    {
        get
        {
            return _score;
        }
        set
        {
            _score = value;
        }
    }

    void Start() {
        _timeCounter = FindObjectOfType<TimeCounter>();
    }

    public void AddScore()
    {
        _score += _scorePerCard;
    }

    public void CalculateEndScore
    {
        _score += Mathf.Clamp(_initialTimeScoreBonus - _bonusScorePerSecondLost * _timeCounter.timeCounted, 0, _initialTimeScoreBonus);
    }
}

Come back to “GameManager” and modify it, so it should look like this:

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

    private ScoreManager _scoreManager; //<---
    [SerializeField]
    private GameObject _winMenu; //<---
    [SerializeField]
    private TimeCounter _timeCounter;

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

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

    void Start()
    {
        _scoreManager = FindObjectOfType<ScoreManager>(); //<---
        _timeCounter = FindObjectOfType<TimeCounter>(); //<---
    }

    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();

                _scoreManager.AddScore(); //<---
                _scoreManager.AddScore(); //<---

                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)
        {
            _winMenu.SetActive(true); //<---
            _timeCounter.countTime = false; //<---
            _secondCard.CalculateEndScore(); //<---
        }
    }

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

        return false;
    }
}



After that fill “WinMenu” field with “WinMenu” GameObject from Canvas and add new script “SetScoreText” to “ScoreText” in Canvas.

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

// © 2017 TheFlyingKeyboard 
// theflyingkeyboard.net

public class SetScoreText : MonoBehaviour {
    [SerializeField]
    private Text _scoreText;

    private ScoreManager _scoreManager;

  // Use this for initialization
  void Start () {
        _scoreManager= FindObjectOfType<ScoreManager>();
        _scoreText.text = "Score: " + _scoreManager.score;
    }
}

When the script was created fill “ScoreText” field with “ScoreText” GameObject.

And finally Change Camera Background Color to: #BDC2F900.

The game should be working right now. Have fun with it and if you want you can implement some features like:

  • Generate amount of cards, depending on user input in begining of the game;
  • Add Pause Menu
  • Add More Cards
  • Add Sound Effect, when card is being flipped
  • Add Music to the game
  • Add Flip Animation

Thanks for reading :).

Memory Game Tutorial Part 3 – Time Counter And Score Manager
Tagged on:             

Leave a Reply

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