Making lives in Block Breaker

@Rob

Sure I’ll label them as I go too:

Music Player

using UnityEngine;
using System.Collections;

public class MusicPlayer : MonoBehaviour {
    static MusicPlayer instance = null;

    void Awake()
    {
        if (instance != null)
        {
            DestroyObject(gameObject);
        }
        else
        {
            instance = this;
            GameObject.DontDestroyOnLoad(gameObject);
        }
        }     	
	}

Paddle

 using UnityEngine;

 public class Paddle : MonoBehaviour {

    public bool autoplay = false;
    private Ball ball;

    void Start()
    {
        ball = FindObjectOfType<Ball>();
    }
    // Update is called once per frame
    void Update()
    {
        if (!autoplay)
        {
            MoveWithMouse();
        }else{
            AutoPlay();
        }
    }

    void AutoPlay()
    {
        Vector3 paddlePos = new Vector3(0.5f, transform.position.y, 0f);
        Vector3 ballPos = ball.transform.position;
        paddlePos.x = Mathf.Clamp(ballPos.x, 0.5f, 15.5f);
        this.transform.position = paddlePos;
    }
    void MoveWithMouse(){ 
        Vector3 paddlePos = new Vector3(0.5f, transform.position.y, 0f);
        float mousePosInBlocks = Input.mousePosition.x / Screen.width * 16;
        paddlePos.x = Mathf.Clamp (mousePosInBlocks, 0.5f, 15.5f);
        this.transform.position = paddlePos;
    }
    }

Ball

using UnityEngine;
using System.Collections;

public class Ball : MonoBehaviour {
    private Paddle paddle;
    private bool hasStarted = false;
    private Vector3 paddleToBallVector;

	// Use this for initialization
	void Start () {
        paddle = FindObjectOfType<Paddle>();
        paddleToBallVector = this.transform.position - paddle.transform.position;
	}

        // Update is called once per frame
        void Update() {
        if (!hasStarted) { 
        this.transform.position = paddle.transform.position + paddleToBallVector;

        if (Input.GetMouseButtonDown(0)) {
            hasStarted = true;
            gameObject.GetComponent<Rigidbody2D>().velocity = new Vector2(2f, 10f);
        }

    }
    }
    void OnCollisionEnter2D(Collision2D collision)
    {
        // Ball does not trigger sound when brick is destoyed.
        // Not 100% sure why, possibly because brick isn't there.
        Vector2 tweak = new Vector2(Random.Range(0f, 0.2f), Random.Range(0f, 0.2f));
        if (hasStarted)
        {
            GetComponent<AudioSource>().Play();
            gameObject.GetComponent<Rigidbody2D>().velocity += tweak;
        }
    }
    }

Brick

using UnityEngine;
using System.Collections;

public class Brick : MonoBehaviour {

    public AudioClip crack;
    public Sprite[] hitSprites;
    private int timesHit;
    private LevelManager levelManager;
    public static int breakableCount = 0;
    public GameObject smoke;
    private bool isBreakable;
    // Use this for initialization
    void Start () {
        isBreakable = (this.tag == "Breakable");
        // Keep track of Breakable Bricks
        if (isBreakable){
            breakableCount++;
        }

        timesHit = 0;
        levelManager = FindObjectOfType<LevelManager>();
    }
	
	// Update is called once per frame
	void Update () {
	
	}
    void OnCollisionEnter2D(Collision2D collision){
        AudioSource.PlayClipAtPoint(crack, transform.position, 5f);
        if (isBreakable){
            HandleHits();
        }
    }
    void HandleHits () {
            timesHit++;
            int maxHit = hitSprites.Length + 1;
            if (timesHit >= maxHit) {
            breakableCount--;
            levelManager.BrickDestroys();
            PuffSmoke();
            DestroyObject(gameObject);
        }
            else {
                LoadSprites();
            }
    }

    void PuffSmoke()
    {
        GameObject smokePuff = Instantiate(smoke, transform.position, Quaternion.identity) as GameObject;
        smokePuff.GetComponent<ParticleSystem>().startColor = gameObject.GetComponent<SpriteRenderer>().color;
    }

    void LoadSprites() {
        int spriteIndex = timesHit - 1;
        if (hitSprites[spriteIndex]){
            GetComponent<SpriteRenderer>().sprite = hitSprites[spriteIndex];
        }
    }
    //TODO Delete later
    void SimulateWin() {
        levelManager.LoadNextLevel();
    }
    }

Lose Collider

using UnityEngine;
using System.Collections;
using System;

public class LoseCollider : MonoBehaviour {

    private LevelManager levelManager;

    void start() {

    }
    void OnTriggerEnter2D(Collider2D trigger) {
    }
    void OnCollisionEnter2D(Collision2D collision){
        levelManager = FindObjectOfType<LevelManager>();
        levelManager.LoadLevel("Lose");
    }
    void update()
    {
    }
    }

Level Manager

using UnityEngine;
using System.Collections;
using UnityEditor.SceneManagement;

public class LevelManager : MonoBehaviour {
    private int Lives;
    private LoseCollider loseCollider;
    public GameObject playerLives;

    void Start(){
        loseCollider = FindObjectOfType<LoseCollider>();
        Lives = 5;
    }

    public void LoadLevel(string name){
        Brick.breakableCount = 0;
        Application.LoadLevel(name);
    }
    public void QuitRequest(){
        Application.Quit();
    }
    public void LoadNextLevel() {
        Brick.breakableCount = 0;
        Application.LoadLevel(Application.loadedLevel + 1);
    }
    public void BrickDestroys()
    {
        if (Brick.breakableCount <= 0) {
            LoadNextLevel();
        }
    }
    public void LivesCount(){
        if (Lives <= 0) {
            Application.LoadLevel("Lose");
        }
    }
    }

Smoke Destroyer (This is a different script I’ve been having trouble with. I’m trying to prevent the hiarachy filling up with smoke instances, leading to possible slow-down on the game and machine and it’s been semi-effective for the moment. The lives is the major thing I want to get covered first though.)

That should be every script. I apologise if most of them you didn’t need, but I thought it best to include all of them as you stated.

1 Like

Thanks for this Aron, I am looking at it now. :slight_smile:

Hi Aron,

I have spent a few hours on this for you and have something that works…

Rather than using the code above, I logged into Udemy and downloaded the completed Block Breaker solution from the course, it shouldn’t really be much different from what you provided me with, but of course it has all the scenes and assets which made it a bit easier for me to test that what I was going to post would actually work! :slight_smile:

Please bear that in mind when you try it, as if you have added anything specific that isn’t in the course version my code below will invariably break it - backups! :slight_smile:


Please try the following steps;

  • Select your Start scene and add an empty game object, rename it to GameManager
  • Select the Scripts folder under Assets and create a new C# script, rename it GameManager
  • Attach the GameManager script to the GameManager object in the hierarchy
  • Drag the GameManager object to the Prefabs folder under Assets

Note: The creation of the Prefab is not strictly necessary, as we will only have one of these, I made it a prefab early on whilst testing a couple of different approaches and hadn’t changed it back - follow the above for now until you have a working solution, then feel free to hack it to bits :slight_smile:


Now for the code changes;

  • Open Ball.cs from the Assets / Scripts folder
  • Replace the existing code with the following;

using UnityEngine;

public class Ball : MonoBehaviour
{

    private Paddle _paddle = null;
    private bool _inMotion = false;
    private Vector3 _paddleToBallVector;

    // Initialisation
    private void Start()
    {
        Initialise();
    }

    /// <summary>
    /// Update
    /// </summary>
    private void Update()
    {
        DetermineMotionState();
    }

    /// <summary>
    /// Sets the position of the Ball to the Paddle
    /// </summary>
    private void Initialise()
    {
        _paddle = GameObject.FindObjectOfType<Paddle>();
        _paddleToBallVector = this.transform.position - _paddle.transform.position;
    }

    /// <summary>
    /// Determins the current state of the Ball's motion. If the Ball isn't in motion it's position is reset.
    /// </summary>
    private void DetermineMotionState()
    {
        if (_inMotion != true)
        {
            SetLaunchPosition();
            LaunchOnMouseClick();
        }
    }

    /// <summary>
    /// Sets the launch position of the Ball on the Paddle and keeps it there until launch
    /// </summary>
    private void SetLaunchPosition()
    {
        this.transform.position = _paddle.transform.position + _paddleToBallVector;
    }

    /// <summary>
    /// Launches the Ball upon mouse click
    /// </summary>
    private void LaunchOnMouseClick()
    {
        if (Input.GetMouseButtonDown(0) == true)
        {
            _inMotion = true;
            this.GetComponent<Rigidbody2D>().velocity = new Vector2(2f, 10f);
        }
    }

    void OnCollisionEnter2D(Collision2D collision)
    {
        // Ball does not trigger sound when brick is destoyed.
        // Not 100% sure why, possibly because brick isn't there.
        Vector2 tweak = new Vector2(Random.Range(0f, 0.2f), Random.Range(0f, 0.2f));

        if (_inMotion)
        {
            GetComponent<AudioSource>().Play();
            GetComponent<Rigidbody2D>().velocity += tweak;
        }
    }

    /// <summary>
    /// Resets the Ball's position after exiting the PlaySpace
    /// </summary>
    public void ResetLaunchPosition()
    {
        _inMotion = false;
    }
}

  • Open LevelManager.cs from the Assets / Scripts folder
  • Replace the existing code with the following;

using UnityEngine;
using UnityEngine.UI;
using System.Linq;

public class LevelManager : MonoBehaviour {

    /// <summary>
    /// Initialisation
    /// </summary>
    private void Start()
    {
        if (GameObject.Find("Canvas"))          // This is a bit messy.  It checks to see if there is a canvas, if so, updates the remaining lives
        {                                       // which prevents a null reference exception error occuring on non-playable levels (Win, Loose, Start)
            UpdateUIPlayerLivesRemaining();     
        }
    }

	public void LoadLevel(string name){
		Debug.Log ("New Level load: " + name);
		Brick.breakableCount = 0;
		Application.LoadLevel (name);
	}

	public void QuitRequest(){
		Debug.Log ("Quit requested");
		Application.Quit ();
	}
	
	public void LoadNextLevel() {
		Brick.breakableCount = 0;
		Application.LoadLevel(Application.loadedLevel + 1);
	}
	
	public void BrickDestoyed() {
		if (Brick.breakableCount <= 0) {
			LoadNextLevel();
		}
	}

    /// <summary>
    /// Updates the player lives UI.Text object with the player's remaining lives
    /// </summary>
    public void UpdateUIPlayerLivesRemaining()
    {
        Text uiDisplayPlayerLives = GetTextObjectByName("PlayerLives");
        GameManager gameManager = GameObject.FindObjectOfType<GameManager>();

        uiDisplayPlayerLives.text = "Lives " + gameManager.PlayerLivesRemaining.ToString();
    }

    /// <summary>
    /// Resets the location of the Ball to the Paddle
    /// </summary>
    public void ResetBall()
    {
        Ball ball = GameObject.FindObjectOfType<Ball>();
        ball.ResetLaunchPosition();
    }



    // Helper method which could be moved to a separate class later

    /// <summary>
    /// Returns a UI.Text object for the specified name
    /// </summary>
    /// <param name="name">The name of the UI.Text object to return</param>
    /// <returns></returns>
    private Text GetTextObjectByName(string name)
    {
        var canvas = GameObject.Find("Canvas");         // Hard coded, assumes the canvas will always be called "Canvas"
        var texts = canvas.GetComponentsInChildren<Text>();

        return texts.FirstOrDefault(textObject => textObject.name == name);
    }
}

  • Open GameManager.cs from the Assets / Scripts folder
  • Replace the existing code with the following;

using UnityEngine;

public class GameManager : MonoBehaviour {

    // GameManager instance
    private GameManager _gameManager = null;

    // Player
    private int _playerDefaultLives = 3;        // Hard coded value
    private int _playerLivesRemaining = 0;
   

    /// <summary>
    /// Returns the number of lives remaining for the player
    /// </summary>
    public int PlayerLivesRemaining
    {
        get { return _playerLivesRemaining; }
    }


    /// <summary>
    /// Pre-Initialisation
    /// </summary>
    private void Awake()
    {
        // singleton pattern for GameManager
        if (_gameManager != null)
        {
            Destroy(gameObject);
        }
        else
        {
            _gameManager = this;

            GameObject.DontDestroyOnLoad(gameObject);
        }
    }

    /// <summary>
    /// Initialises a new game by setting the player lives to the default value (3)
    /// </summary>
    public void NewGame()
    {
        _playerLivesRemaining = _playerDefaultLives;
    }

    /// <summary>
    /// Decreases the player's lives by one and checks for a game over state.
    /// </summary>
    public void PlayerLosesLife()
    {
        LevelManager levelManager = GameObject.FindObjectOfType<LevelManager>();

        --_playerLivesRemaining;

        if (_playerLivesRemaining <= 0)
        {
            GameOver();
        }
        else
        {
            levelManager.UpdateUIPlayerLivesRemaining();
            levelManager.ResetBall();
        }
    }

    /// <summary>
    /// Loads the "Loose" scene ;)   and destroys the GameManager
    /// </summary>
    private void GameOver()
    {
        LevelManager levelManager = GameObject.FindObjectOfType<LevelManager>();

        levelManager.LoadLevel("Loose Screen");

        Destroy(this);
    }
}

  • Open LoseCollider.cs from the Assets / Scripts folder
  • Replace the existing code with the following;

using UnityEngine;
using System.Collections;

public class LoseCollider : MonoBehaviour {
    
    private GameManager _gameManager;

    /// <summary>
    /// Pre-Initialisation
    /// </summary>
    private void Awake()
    {
        _gameManager = GameObject.FindObjectOfType<GameManager>();
    }

    /// <summary>
    /// Handles the OnTriggerEnter2D event triggered by another object entering a trigger collider attached to the LoseCollider
    /// </summary>
    /// <param name="collider">The other Collider2D involved in the collision</param>
    private void OnTriggerEnter2D(Collider2D collider)
    {
        _gameManager.PlayerLosesLife();
    }
}

Now, back into Unity, we need to make some minor changes;

  • Open the Level_01 scene
  • Create a new UI -> Text game object, rename it to “PlayerLives” (no space in between the words)
  • Ensure the Canvas that was added is called “Canvas”
  • Move the Text object to a visible location on the scene (I’d suggest top left corner)
  • Drag the Canvas object from the hierarchy to the Prefabs folder under Assets
  • Save the scene
    -
  • Open the Level_02 scene
  • Drag the Canvas prefab into the hierarchy
  • Save the scene
    -
  • Open the Level_03 scene
  • Drag the Canvas prefab into the hierarchy
  • Save the scene

We also need to rewire the Start button as we need the OnClick() event to handle two tasks;

  • Open the Start Menu scene
  • Select the Start Button in the hierarchy
  • Within the Inspector, click on the - (minus sign) under the OnClick() event for the Button Script

There should now be no methods being call on the OnClick() event.

  • Click the + (plus sign) under the OnClick() event for the Button Script
  • Select Editor and Runtime
  • Drag the GameManager object from the hierarchy onto the Object field in the OnClick() event handler
  • From the drop down menu on the right, select GameManager and then New Game as the method
    -
  • Click the + (plus sign) under the OnClick() event for the Button Script
  • Select Editor and Runtime
  • Drag the LevelManager object from the hierarchy onto the Object field in the OnClick() event handler
  • From the drop down menu on the right, select LevelManager and then LoadLevel as the method
  • Enter “Level_01” into the parameter field that appears after the above step
  • Save the scene

Here is a screenshot of what this should look like in the Inspector;

  • With the Start Menu scene selected, click Play

  • Fire the ball and miss it, you should see lives drop to 2
  • Repeat twice more and you should be taken to the Loose Screen scene :wink:

Hope this helps :slight_smile:

@Rob

Hi Rob, this has certainly helped and I had to fix one or two spelling issues (I have fixed Ben’s mis-spelling of Loose whilst following along so the new scripts didn’t like that and I have the BrickDestroyed called BrickDestroys, plus there was a missing R too, but those were easy fixes. Now it just doesn’t seem to like something in the level manager script, but I can’t place my finger on it…it’s not red or showing any error at all, just saying the object is never referenced.

Error:
NullReferenceException: Object reference not set to an instance of an object
LevelManager.UpdateUIPlayerLivesRemaining () (at Assets/Scripts/LevelManager.cs:54)
LevelManager.Start () (at Assets/Scripts/LevelManager.cs:15)

I’ve tried to figure out what ti might be, going around the manager at those lines, but can’t see a single problem and the number fails to go down, nor even taken it to the lose screen. The lines mentioned are:

LevelManager.cs.54 = uiDisplayPlayerLives.text = "lives x " + gameManager.PlayerLivesRemaining.ToString();

LevelManager.cs.15 = UpdateUIPlayerLivesRemaining();

Beyond that, everything else appears to run smoothly, it just doesn’t seem to understand what you’re referencing and taking a look I’m not certain I am sure either. My assumption is something about the GameManager and maybe the use of “_” in certain areas, but I removed them and found it didn’t work so that’s another deadend.

I am sorry about how much time this must be taking up and really appreciate how much you’ve helped. I hope I don’t cause more headaches like this in the future.

You are more than welcome Aron, and it’s no trouble at all - my apologies for any spelling mistakes in the instructions above, whilst I had the game working as intended, I was against the clock on the write up of the instructions as I had to pick up my son from school - made it though :slight_smile:

Just to check, are you saying that the number of lives on the playable scenes isn’t going down? If so, the null reference exception you are referring to relates to the levelManager not being able to see the UI Text object. Is yours named the same as mine in the code above?

For example;

Create a new UI -> Text game object, rename it to “PlayerLives” (no space in between the words)

If you didn’t do this step because you already had a canvas and a UI Text object, chances are you have it named to something other than what I specify here, so the levelManager just can’t see it.

Something worth checking.

@Rob

ahh understandable. Don’t have kids myself, but I know how frustraiting it is to get to schools on time. Worse when you’re extended family and teachers need to not only know you are coming, but need to have seen you before, but that’s a headache for a whole other discussion.

No, I definantly did have it already named “PlayerLives”, but I also went ahead to make the UI text again because I believed that keeping it may keep the issue, but as far as I can see it’s all spelt right. PlayerLives, Canvas, GameManager. It all appears to work fine my end…

Hi Aron, so it’s all good? All working as it should be? Counting down when you miss the ball etc… but it’s still producing the null reference exception error? Is that correct?

no what i meant was the number of lives is updated in the box to being 5 (which is why I set it at) but it never goes down, nor does it finish the level.

Sorry Aron, lost me a little, what box? A field in the Inspector, or the UI Text object? Or something else?

Sorry I should’ve specified.
this error comes up in the scene:

Error:
NullReferenceException: Object reference not set to an instance of an object
LevelManager.UpdateUIPlayerLivesRemaining () (at Assets/Scripts/LevelManager.cs:54)
LevelManager.Start () (at Assets/Scripts/LevelManager.cs:15)

And even though the UI Text object does display the current number of lives, it never decreases and is never ends the game when hitting the losecollider over 5 times.

I see… ok, so one way to start debugging the problem would be to add some Debug.Log(" a message "); statements in the various methods that are being run so that we can see what’s happening and when.

However, before we go down that road, I am assuming that this is on scene 1, so, can you select scene_01, take a screenshot of Unity, with all of the items expanded in the hierarchy view for me please (e.g the arrows next to PlaySpace and Canvas, don’t worry about doing Brick as it may push the objects too far down for the screen shot).

Let’s compare… this is what I have;

…and just to confirm, you have set the number of lives to 5 where? In the text field of the inspector or, in this line of code from GameManager?

private int _playerDefaultLives = 3; // Hard coded value

I had changed it in the GameManager. I had left the text in the box as “lives x” and looked through the script to change how the text reads to:

uiDisplayPlayerLives.text = "lives x " + gameManager.PlayerLivesRemaining.ToString();

I did this so I can tell the difference when I enter the game and everytime it then says “lives x 5” however the number never goes down, but the number is associated with the script.

When you start the game from within Unity, are you starting it from the Start Menu scene or the Level_01 scene? The reason being, the GameManager is only attached to the Start Menu scene, as such you have to run it from that scene.

Update

I can get the same error message if I launch the game from Scene_01;

NullReferenceException: Object reference not set to an instance of an object
LevelManager.UpdateUIPlayerLivesRemaining () (at Assets/Scripts/LevelManager.cs:48)
LevelManager.Start () (at Assets/Scripts/LevelManager.cs:14)

Please double click the Start Menu scene and then run the game from within Unity and let’s see what happens.

Yep, I’ve been loading it from the start scene and the error comes up when I enter Level_1. It’s fine until I start that level.

Ok, can you post the screenshot of Scene_01 hierarchy then please, with the items expanded, except for Bricks.

Also, can you click on the UI Text object, so that its properties are viewable in the Inspector and take a screenshot of that also please.

Hiarachy:

Text object UI:

Before we dig deeper, one thing that caught me out the other week was not making the size of the UI Text object wide enough for the text to go in it - I spent hours trying all sorts of things trying to work out what was wrong with the code, turned out to be something simple that I missed. I take it the size of the UI Text object in your canvas is wide enough to receive the text?

Other than that…

/// <summary>
/// Updates the player lives UI.Text object with the player's remaining lives
/// </summary>
public void UpdateUIPlayerLivesRemaining()
{
    Text uiDisplayPlayerLives = GetTextObjectByName("PlayerLives");
    GameManager gameManager = GameObject.FindObjectOfType<GameManager>();

    uiDisplayPlayerLives.text = "Lives " + gameManager.PlayerLivesRemaining.ToString();
}

I renamed “PlayerLives” to “PlayerLived” on mine just as a test, I was able to reproduce the same error on Scene_01 as you have mentioned whilst starting from Start Menu. This really would indicate that it is not finding the UI Text object.

It’s quite difficult to resolve this remotely as I don’t have your solution at hand. I’m guessing that the project you are having the issue with was the one you were already working on, rather than the completed one at the end of the Unity course, with my changes then applied?

Pop up a copy of the GameManager script for me and the LevelManager script if you have time and I’ll have a read through to see if I can spot anything.

Don’t worry, today’s my day off and I have plenty of time.

for the scripts I copy and pasted what you had, albeit changing the name of lives as mentioned earlier because I think “lives x #” looks better than “Lives #” and the font I’m using doesn’t like capital letters either:

LevelManager:

using UnityEngine;
using UnityEngine.UI;
using System.Linq;

public class LevelManager : MonoBehaviour
{

/// <summary>
/// Initialisation
/// </summary>
private void Start()
{
    if (GameObject.Find("Canvas"))          // This is a bit messy.  It checks to see if there is a canvas, if so, updates the remaining lives
    {                                       // which prevents a null reference exception error occuring on non-playable levels (Win, Loose, Start)
        UpdateUIPlayerLivesRemaining();
    }
}

public void LoadLevel(string name)
{
    Debug.Log("New Level load: " + name);
    Brick.breakableCount = 0;
    Application.LoadLevel(name);
}

public void QuitRequest()
{
    Debug.Log("Quit requested");
    Application.Quit();
}

public void LoadNextLevel()
{
    Brick.breakableCount = 0;
    Application.LoadLevel(Application.loadedLevel + 1);
}

public void BrickDestroyed()
{
    if (Brick.breakableCount <= 0)
    {
        LoadNextLevel();
    }
}

/// <summary>
/// Updates the player lives UI.Text object with the player's remaining lives
/// </summary>
public void UpdateUIPlayerLivesRemaining()
{
    Text uiDisplayPlayerLives = GetTextObjectByName("PlayerLives");
    GameManager gameManager = GameObject.FindObjectOfType<GameManager>();

    uiDisplayPlayerLives.text = "lives x " + gameManager.PlayerLivesRemaining.ToString();
}

/// <summary>
/// Resets the location of the Ball to the Paddle
/// </summary>
public void ResetBall()
{
    Ball ball = GameObject.FindObjectOfType<Ball>();
    ball.ResetLaunchPosition();
}



// Helper method which could be moved to a separate class later

/// <summary>
/// Returns a UI.Text object for the specified name
/// </summary>
/// <param name="name">The name of the UI.Text object to return</param>
/// <returns></returns>
private Text GetTextObjectByName(string name)
{
    var canvas = GameObject.Find("Canvas");         // Hard coded, assumes the canvas will always be called "Canvas"
    var texts = canvas.GetComponentsInChildren<Text>();

    return texts.FirstOrDefault(textObject => textObject.name == name);
}
}

GameManager:
using UnityEngine;

public class GameManager : MonoBehaviour
{

// GameManager instance
private GameManager gameManager = null;

// Player
private int playerDefaultLives = 5;        // Hard coded value
private int playerLivesRemaining = 0;


/// <summary>
/// Returns the number of lives remaining for the player
/// </summary>
public int PlayerLivesRemaining
{
    get { return playerLivesRemaining; }
}


/// <summary>
/// Pre-Initialisation
/// </summary>
private void Awake()
{
    // singleton pattern for GameManager
    if (gameManager != null)
    {
        Destroy(gameObject);
    }
    else
    {
        gameManager = this;

        GameObject.DontDestroyOnLoad(gameObject);
    }
}

/// <summary>
/// Initialises a new game by setting the player lives to the default value (3)
/// </summary>
public void NewGame()
{
    playerLivesRemaining = playerDefaultLives;
}

/// <summary>
/// Decreases the player's lives by one and checks for a game over state.
/// </summary>
public void PlayerLosesLife()
{
    LevelManager levelManager = FindObjectOfType<LevelManager>();

    --playerLivesRemaining;

    if (playerLivesRemaining <= 0)
    {
        GameOver();
    }
    else
    {
        levelManager.UpdateUIPlayerLivesRemaining();
        levelManager.ResetBall();
    }
}

/// <summary>
/// Loads the "Loose" scene ;)   and destroys the GameManager
/// </summary>
private void GameOver()
{
    LevelManager levelManager = GameObject.FindObjectOfType<LevelManager>();

    levelManager.LoadLevel("Lose");

    Destroy(this);
}
}

On you Start Menu scene, you have a canvas, is it called Play Space or Canvas?

Also, can you pop up a copy of the lose collider script.

It’s called Canvas

Lose Collider:

using UnityEngine;
using System.Collections;

public class LoseCollider : MonoBehaviour
{

private GameManager gameManager;

/// <summary>
/// Pre-Initialisation
/// </summary>
private void Awake()
{
    gameManager = GameObject.FindObjectOfType<GameManager>();
}

/// <summary>
/// Handles the OnTriggerEnter2D event triggered by another object entering a trigger collider attached to the LoseCollider
/// </summary>
/// <param name="collider">The other Collider2D involved in the collision</param>
private void OnTriggerEnter2D(Collider2D collider)
{
    gameManager.PlayerLosesLife();
}
}

Privacy & Terms