Check character health before destroying collectibles
Tutorial
·
Beginner
·
+10XP
·
30 mins
·
(1099)
Unity Technologies

In this tutorial, you’re going to adjust the HealthCollectible script so the collectible only gets destroyed if the player character actually needs more health.
By the end of this tutorial, you’ll be able to define and use a property to determine whether the collectible should be destroyed.
1. Overview
In the previous two tutorials, you set up a basic health system and created a collectible GameObject to give the player character a health increase. Right now the CollectibleHealth GameObject gets destroyed when the player character collides with it, whether the character actually needs the health increase or not. You’re going to adjust the collectible so it only gets destroyed if the player character actually needs more health; this is a much more efficient way to manage in-game resources.
By the end of this tutorial, you’ll be able to define and use a property to determine whether the collectible should be destroyed.
Working on your own project?
This tutorial is part of Beginner 2D: Adventure Game and refers to the game project for that course, but this information will be helpful for any beginner creator who wants to set up a basic health system in their game.
Note: For the purposes of this tutorial, we chose to use the Ruby’s Adventure asset set, and the file paths used in instructions will reflect this. If you chose another asset set, the file names will be the same, but in your corresponding theme folder.
2. Check the player character’s current health
If you want to adjust your health collectible so that it only gets consumed if the player character needs more health, the collectible script needs to determine whether or not the character is currently at full health.
To add the check to your script, follow these instructions:
1. Open the HealthCollectible script in your IDE.
At the moment, the code that increases the player’s health is executed whenever the physics system recognizes the player character GameObject due to its PlayerController script.
2. Try to adjust the script so the instructions that increase health and destroy the GameObject only get executed if apart from the previous condition, the player character’s currentHealth value is less than the maxHealth value.
When you’ve had a go, save your changes then read on to check the possible solutions.
Important: You’ll need to fix an issue before your code works in Unity, so don’t be concerned if you test proactively and encounter an error.
The if condition
You can use syntax that you’ve previously encountered to write the if condition for executing the code:
if (controller.currentHealth < controller.maxHealth)Here, the "less than" symbol (<) means that the code will only be executed if the currentHealth value in the PlayerController script is less than the maxHealth value.
Nested if statements
One way to add this additional condition is to nest a second if statement inside your first, with both statements wrapped around the code that passes the parameter to the ChangeHealth function and destroys the CollectibleHealth GameObject.
void OnTriggerEnter2D(Collider2D other)
{
   PlayerController controller = other.GetComponent<PlayerController>();
   if (controller != null)
   {
     if (controller.currentHealth < controller.maxHealth)
     {
       controller.ChangeHealth(1);
       Destroy(gameObject);
     }
   }
}
This nested approach isn’t the most elegant solution and it won’t always scale well for complex conditional situations, but it does the job!
A single updated if statement
There’s a more efficient approach you can use to include both conditions in a single statement: the and (&&) conjunction operator. Both the condition before and the condition after the && operator must be met for the code inside to be executed.
void OnTriggerEnter2D(Collider2D other)
{
   PlayerController controller = other.GetComponent<PlayerController>();
   if (controller != null && controller.currentHealth < controller.maxHealth)
   {
       controller.ChangeHealth(1);
       Destroy(gameObject);
   }
}
This code has the same functionality as the nested if statements, but it’s neater and easier to scale in complex situations. You can use either approach in your HealthCollectible script.
3. Define a property in the PlayerController script
You may be anticipating an error that you’ve previously encountered: the currentHealth variable is private, so your HealthCollectible script can’t currently access it. You can make the variable public, but when you make code public that doesn’t need to be you are increasing the chance of annoying bugs that you’ll need to fix later. For example, if currentHealth is public then another script could change it to a value above the maxHealth value — a function like ChangeHealth that can clamp the possible values is a much safer way to control this functionality.
The HealthCollectible script doesn’t need to write to the currentHeath variable as part of its condition checks, it just needs to read the variable’s current value. To facilitate this you can use a read-only property, a method that you can use to read the value of a private variable.
To define a property to read the currentHeath value, follow these instructions:
1. Open the PlayerController script in your IDE.
2. At the top of the script, on a new line, above the declaration of the currentHealth variable, add the following code:
public int health { get { return currentHealth; }}Here’s an explanation of this code:
- The property definition is similar to a variable declaration. It has an access level keyword (public), a type (int), and a name (health).
- This definition then has some unfamiliar syntax: two sets of braces (code blocks), one nested inside the other.
- The outer block contains the keyword get and a second block. True to its name, the purpose of the keyword is to get whatever is in the nested block so that information can be read in other scripts.
- The inner block returns the currentHealth value. The compiler treats this block like a normal function, so you can add instructions to declare a variable, complete computations or call other functions here. However, in this case all you need to do is get the value of the currentHealth variable.
3. Save your changes.
4. Use the health property in your health collectible
Now you can update the HealthCollectible script to use the new property:
1. Return to the HealthCollectible script in your IDE.
2. Update the if statement conditions to use the health property rather than the currentHealth variable directly:
if (controller != null && controller.health < controller.maxHealth)Note: If you are using nested if statements, make this same change to the inner statement.
3. Save your changes.
4. Return to the Unity Editor and test your updates. Now, if the player character has full health when it collides with the health collectible, the CollectibleHealth GameObject won’t be destroyed.
5. Check your scripts
If you’re completing the 2D Beginner course, take a moment to check that your scripts are correct before continuing.
PlayerController.cs
Important: If you completed any extension work in your script, this will not be reflected in the reference script below.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour
{
  // Variables related to player character movement
  public InputAction MoveAction;
  Rigidbody2D rigidbody2d;
  Vector2 move;
  public float speed = 3.0f;
  // Variables related to the health system
  public int maxHealth = 5;
  public int health { get { return currentHealth; }}
  int currentHealth = 1;
  // Start is called before the first frame update
  void Start()
  {
     MoveAction.Enable();
     rigidbody2d = GetComponent<Rigidbody2D>();
     //currentHealth = maxHealth;
  }
 
  // Update is called once per frame
  void Update()
  {
     move = MoveAction.ReadValue<Vector2>();
  }
  // FixedUpdate has the same call rate as the physics system
  void FixedUpdate()
  {
     Vector2 position = (Vector2)rigidbody2d.position + move * speed * Time.deltaTime;
     rigidbody2d.MovePosition(position);
  }
  public void ChangeHealth (int amount)
  {
     currentHealth = Mathf.Clamp(currentHealth + amount, 0, maxHealth);
     Debug.Log(currentHealth + "/" + maxHealth);
  }
}HealthCollectible.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HealthCollectible : MonoBehaviour
{
void OnTriggerEnter2D(Collider2D other)
{
   PlayerController controller = other.GetComponent<PlayerController>();
   if (controller != null && controller.health< controller.maxHealth)
   {
       controller.ChangeHealth(1);
       Destroy(gameObject);
   }
}
}
6. Next steps
You’ve fully configured the health system for your game, but at the moment there’s no real need for it because there’s nothing that can damage the player. In the next tutorial you’ll add static damage zones that decrease the player character's health, the most basic challenge that your players will encounter.