Breakout Clone 8: Adding a few more levels and tracking score

2023-04-03

The next couple of things I want to do are fairly simple, so I thought I could combine them into a single post.

Adding a few more levels

First we'll add a few more levels to the game. Unity calls these "Scenes".

This is fairly straightforward; all I did was duplicate the existing level a couple of times and add more blocks in different arrangements. In the project's build settings, I made sure that the levels appeared in the correct order. The victory scene should follow immediately after the last level, and the failure screen should be last level in the build.

We'll keep the logic for transitioning scenes on the GameSession:

  public void LoadNextLevel() {
    int nextSceneIndex = SceneManager.GetActiveScene().buildIndex + 1;
    SceneManager.LoadScene(nextSceneIndex);
  }

And now we just need to call it.

In my Destructible Blocks post, I added a DestroyBlockIfDead method to the Block object that can detect when to destroy the game object. This the perfect place to check if there are any remaining Blocks on the screen, and transition to the next scene if there aren't any:

   private void DestroyBlockIfDead() {
    if (currentHealth > 0) {
      return;
    }

    GameSession gameSession = FindObjectOfType<GameSession>(); // NEW

    int numberOfBlocksRemaining = GameObject.FindGameObjectsWithTag("Block").Length - 1; // NEW
    if(numberOfBlocksRemaining == 0) { // NEW
      gameSession.LoadNextLevel(); // NEW
    } // NEW

    Destroy(gameObject);
  }

Keeping track of the player's score

Again, back in our Block object, lets add more logic to our DestroyBlockIfDead function:

  // In Block.cs

  // NEW This field will be the value of a particular block.
  [SerializeField] int blockValue = 100;

  private void DestroyBlockIfDead() {
    if (currentHealth > 0) {
      return;
    }

    GameSession gameSession = FindObjectOfType<GameSession>();
    gameSession.AddToScore(blockValue); // NEW

    int numberOfBlocksRemaining = GameObject.FindGameObjectsWithTag("Block").Length - 1;
    if(numberOfBlocksRemaining == 0) {
      gameSession.LoadNextLevel();
    }

    Destroy(gameObject);
  }

And in GameSession, we'll now add the missing AddToScore function:

  // in GameSession.cs

  // The scoreText will be a reference to a text object on the screen
  [SerializeField] int initialScore = 0;
  [SerializeField] TMP_Text scoreText; // from using UnityEngine.UI above

  // NEW
  public void AddToScore(int amount) {
    currentScore += amount;
    UpdateScoreUI();
  }

  // This will update the text being rendered inside the text object
  private void UpdateScoreUI() {
    scoreText.text = "Score: " + currentScore;
  }

In order for this to work, we'll also need to add a text element to our game and hand our GameSession object a reference to it. Since it needs to persist across multiple scenes, I made sure to add the object as a child of the GameSession. That way it won't get destroyed as we transition scenes.

In my final post I'll add in a few items that can drop randomly when a block is destroyed.