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

    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; //<---
            _scoreManager.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 and released under MIT License
// 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:             

11 thoughts on “Memory Game Tutorial Part 3 – Time Counter And Score Manager

  • February 6, 2018 at 5:39 am
    Permalink

    Had some errors that prevented it from working

    Reply
    • February 9, 2018 at 10:58 pm
      Permalink

      I’ll check the tutorial 🙂

      Reply
    • February 12, 2018 at 8:18 pm
      Permalink

      I’ve checked it and it seems to be working.

      Reply
  • February 20, 2018 at 8:46 am
    Permalink

    i have errors at ScoreManager script at lines 42-44

    Reply
    • February 20, 2018 at 8:50 am
      Permalink

      It says a get or set accessor expected

      Reply
      • February 25, 2018 at 10:25 am
        Permalink

        Strange, it works for me :/

        Reply
  • February 24, 2018 at 5:15 am
    Permalink

    got errors too in this part:
    “_secondCard.CalculateEndScore();” for Game Manager.

    Reply
    • February 25, 2018 at 10:23 am
      Permalink

      Fixed it, it should be _scoreManager.CalculateEndScore(); in GameManager 😉

      Reply
  • July 24, 2018 at 10:48 pm
    Permalink

    I am not getting any cards appearing on the game screen. When I look at the scene they are spawning really small near the corner.

    Reply
    • July 24, 2018 at 11:08 pm
      Permalink

      They are not scaling with the resolution or screen size.

      Reply
  • July 24, 2018 at 11:25 pm
    Permalink

    I know what it is now. I was wrong its because the cards are behind the image.

    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