Skip to main content

Environmental Damage: Taking Damage from an Area

This guide shows how to create an environmental obstacle. In this case a section of the map set to be lava that will inflict damage over time while the player stays in the area.

The code has been written so that it can be dropped onto enemy or other objects and have the same effect apply to them.

We need to setup health on a player object as well as set the damage the lava will do and then take that damage every second (or period of your choosing).

A separate death script has been written to reload the scene when health reaches zero.

You can download an example here. After about 10 seconds the scene should reload.

First setup a level with a player object of your choice.

Now we will create a PlayerProperties script to store the player stats and details such as health.

This is a pretty standard script.

  1. Add the SceneManagement tool which is used in points 7 and 8 to reload the scene when health is less than or equal to 0.
  2. Points 2-6 set up player properties for recording the state of the player (or other object) the script is attached to. Note that we will only use the health one here. All of these are public variables so that we can easily modify them from outside of this class.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/* 1.
Added the scene management for reloading the scene on death
This is used just for testing.
*/
using UnityEngine.SceneManagement;

public class PlayerProperties : MonoBehaviour
{
// 2. Player Health
public float health = 100;
// 3. Max player health (not used)
public float maxHealth = 100;
// 4. player armour (not used)
public float armour = 50;
// 5. Max player armour (not used)
public float maxArmour = 100;
// 6. The player name (not used)
public string name = "Pete the Player";

// Update is called once per frame
void Update()
{
// 7. Check if out of health
if(health <= 0) {
// 8. Reload the current scene.
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
}
}

Attach this script to the player object.

Now create a Damage zone object (this can be a prefab if you want to reuse it).

Use an empty gameobject for the base and then add a box collider to it.

Resize this collider to cover the area that you want damage to be inflicted.

Set this collider to be a trigger.

You can also add other details to this object. In this case a transparent orange/brown cube.

Now we need to add a tag (or we could use a layer) to the gameobject with the trigger collider.

Click the dropdown in the inspector for Tag.

Select Add Tag.

Create a tag, in this case one called Lava.

Make sure that you assign the tag to the object.

Now we will create a brief script that contains the damage that the lava should deal.

This script can be reused on multiple objects that you want to store the damage for.

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

public class DamageObject : MonoBehaviour
{
// 1. The amounf of damage to inflict
public float damageAmount = 10;

}

Now we need to add the code to damage the player over time if they are in an area tagged Lava.

This script is attached to the player.

See the points below for explanations of the code

  1. Setup an IEnumerator variable to store the lavaDamage coroutine when it's running.
  2. Create the function to take damage from the player. This is used to create the object used to start the coroutine in point 12. This takes one argument which is the DamageObject script attached to the area we have entered (in this case the lava area).
  3. Here we get the PlayerProperties (or whatever you called the script) that is attached to this object.
  4. Now we set up an infinite loop. This is for the coroutine to run indefinitely.
  5. We update the health variable of the PlayerProperties and take off the amount of damage in the script.
  6. We then wait for one second before repeating and taking off more health.
  7. Now we need to set up the conditions to trigger the event happening. We use the OnTriggerEnter function which takes the Collider that we have hit as an argument.
  8. This is used to check that the collider is working (note that for NavMeshAgents you need to add a rigid body to the object for the colliders to trigger). We can remove this line once we have tested the program.
  9. This if statement checks if the collider has the tag Lava applied to it. If it does we want to run the coroutine as we should be taking damage.
  10. We get the DamageObject script component from the Lava collider. This gives us access to the variable which stores the damage that should be applied to the player.
  11. We not create the IEnumterator object which will be used to run the coroutine. We pass this the DamageObject as a parameter.
  12. Here we start the Coroutine with StartCoroutine passing the IEnumerator variable we assigned data to in 11. This will run indefinitely.
  13. Now we need to check if the player has left the damage area. We use the OnTriggerExit function for this.
  14. We check if the collider we left had the Lava tag.
  15. If this is true we run the StopCoroutine function passing the name if the IEnumerator that we want to stop.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DamagePlayer : MonoBehaviour
{
// 1. Used to run coroutine to take damage over time
IEnumerator lavaDamage;

/* 2.
Function to take damage over time.
Takes the damage object from the lava area.
*/
IEnumerator damageOverTime(DamageObject dmgObj) {
// 3. Get the player properties e.g. script with health.
PlayerProperties pp = GetComponent<PlayerProperties>();
// 4. Always run
while(true) {
// 5. Reduce current health by damage amount
pp.health = pp.health - dmgObj.damageAmount;
// 6. Wait for 1 second before looping.
yield return new WaitForSeconds(1);
}
}

// 7. Runs when object has collided with something
void OnTriggerEnter(Collider col) {
// 8. Test message to make sure collider is working
Debug.Log("Entered damage area");
// 9. Check if the object that was hit has the tag lava
if(col.CompareTag("Lava")) {
// 10. Get the damage object from the object we hit
DamageObject dmgObj = col.GetComponent<DamageObject>();
// 11. Create the IEnumerator to take damage over time
lavaDamage = damageOverTime(dmgObj);
/* 12.
Start the Coroutine to take damage over time
while in the area
*/
StartCoroutine(lavaDamage);
}
}

// 13. Check if we've left a collider
void OnTriggerExit(Collider col) {
// 14. Check if we left the Lava
if(col.CompareTag("Lava")) {
// 15. If we have stop the coroutine
StopCoroutine(lavaDamage);
}
}
}

Save your program and return to Unity.

Test your program.

Well done you now have a working damage over time area effect.