Fall Detection for Platform Game in Untity 3D


In order to detect that a player has fallen to certain death there needs to be some sort of detector. The detector needs to be positioned and scaled to fill the gap at the point of no return. Box colliders tend to work best for this because they can be positioned and scaled easily.

In my game I wanted the player to respawn from the side that they fell from to avoid skipping a tricky area! To achieve this I added one sensor for each major ledge. Upon being hit, the sensor selects itself as the active respawn position for that fall.

The way in which falls are detected and handled will vary with design. I found that there are usually two such sensors for each fall, one before and one after. Or perhaps just one for the start and/or end of a level! Of course there may be occasions where additional sensors are needed; like with high climbs.

Fall Detector Illustration

The mechanism that I created for my game is called a “Fall Detector”. I saved the most common variation of this as a prefab so that I could easily add them as needed. Instances of this prefab can be easily altered to better fit the surrounding environment. Unwanted spawn points can be removed, or new ones can be added simply by duplicating one of the existing ones (Ctrl+D or ⌘+D).

The root-most game object (aka “Fall Detector” is an empty object that contains one or more “Spawn Point” objects and a “Death Zone” object. I will now explain the procedure that I used to set this up in my game.

1. Create an empty object using a relevant name like “Fall Detector”. This object will be saved as a prefab later. It is useful to model this mechanism to fit the most common scenario in your game; whilst not absolutely necessary this can be quite a time saver!

2. Create another empty object using a relevant name like “Death Zone”. Make this object a child of “Fall Detector” using the scene hierarchy panel. This represents the area that will cause the player to either respawn or lose.

3. Add a Box Collider component to the “Death Zone” by selecting the menu Components > Physics > Box Collider.

4. Hold the `Shift` key (to position collider) and drag handles using mouse so that collider fits gap. See annotated screenshot above for an example (green box).

5. Create a new custom script called “FallDetectorDeathZone” and add to “Death Zone”.

The following example script incurs damage onto the player (bunny) and then respawns from the active respawn point. A sound is also played (when specified). It is useful to specify a default sound for the prefab, but this can be overridden for different environments as needed (for example water or lava).

It is a good idea to specify a default respawn point to handle the scenario where a player has somehow avoided a respawn point sensor.

using UnityEngine;
public class FallDetectorDeathZone : MonoBehaviour {

   // Default respawn point to use
   public RespawnPoint defaultRespawnPoint;

   // Sound to play when falling
   public AudioClip fallSound;

   void OnTriggerEnter(Collider collider) {
      if (collider.tag == "Player") {
         RespawnPlayer();
      }
      else {
         // Destroy whatever has set off trigger
         Destroy(collider.gameObject);
      }
   }

   public void RespawnPlayer() {
      Bunny bunny = gameObject
         .FindGameObjectWithTag("Player")
         .GetComponent<Bunny>();

      // Deduct from player lifes
      bunny.IncurDamage(1, fallSound, true);

      // Determine default respawn point automatically?
      if (defaultRespawnPoint == null)
         defaultRespawnPoint = transform
            .GetComponentInChildren<RespawnPoint>();

      // Reposition player
      bunny.transform.position = defaultRespawnPoint.transform.position;
   }

   void OnDrawGizmos() {
      Gizmos.color = new Color(0.0f, 1.0f, 0.0f, 0.2f);
      Gizmos.DrawCube(collider.bounds.center, collider.bounds.size);

      Gizmos.color = new Color(1.0f, 0.0f, 1.0f, 0.2f);
      Gizmos.DrawWireCube(collider.bounds.center, collider.bounds.size);

      foreach (SphereCollider c in GetComponentsInChildren<SphereCollider>()) {
         Gizmos.color = new Color(1.0f, 0.0f, 1.0f, 0.2f);
         Gizmos.DrawWireSphere(c.bounds.center, c.radius * transform.localScale.x);

         Vector3 center = c.transform.position;
         Gizmos.color = new Color(0.0f, 0.0f, 1.0f, 0.7f);
         Gizmos.DrawLine(
            new Vector3(center.x - 0.2f, center.y, center.z),
            new Vector3(center.x + 0.2f, center.y, center.z)
         );
         Gizmos.DrawLine(
            new Vector3(center.x, center.y - 0.2f, center.z),
            new Vector3(center.x, center.y + 0.2f, center.z)
         );
      }
   }

}

Note: The above script includes gizmo rendering to make mechanism easier to work in Unity editor.

6. Create an empty object called “Respawn Point” and again make this a child of “Fall Detector”. This object has two purposes; its origin indicates where the player will respawn from (highlighted with blue arrow in gizmo), and the attached collider causes it to become the active respawn point for the fall detector mechanism.

7. Add a Sphere Collider by selecting Components > Physics > Sphere Collider.

8. Place object so that its origin (blue crosshair) represents the desired respawn point. Hold `Shift` key and adjust collider as needed. In my game I offset the colliders to avoid having the player cheat (by jumping into trigger before reaching other side).

using UnityEngine;
// Respawn points are selected when triggered by player
public class RespawnPoint : MonoBehaviour {

   void OnTriggerEnter(Collider collider) {
      if (collider.tag != "Player")
         return;

      // Set as default trigger point
      FallDetectorDeathZone detector = transform.parent.GetComponent<FallDetectorDeathZone>();
      detector.defaultRespawnPoint = this;
   }

}

I hope that this will be of use to someone. As always, please feel free to leave comments and questions and I will answer them the best I can!

Advertisements

15 thoughts on “Fall Detection for Platform Game in Untity 3D

  1. For the FallDectectorDeathZone script I get an error saying the type or namespace name ‘FallDetectorRespawnPoint’ could not be found. Are you missing a using directive or an assembly reference?
    How do I fix it?

    1. Hello Hayden

      Sorry that was a typo in the above source code, change all occurrences of “FallDetectorRespawnPoint” to “RespawnPoint”.

      On another note, it seems that the WordPress site stripped generics from the source snippets because they look like HTML tags. I have put these back in using the appropriate escape sequence 🙂

  2. Thx for this wonderful blog and tutorial.. I have a question,
    i get an error
    “Assets/Scripts/FallDetectorDeathZone.cs(23,7): error CS0246: The type or namespace name `Bunny’ could not be found. Are you missing a using directive or an assembly reference?”

    doing “using System.Collections;” is not helping, do i have to import anything else?

    thx and regards

  3. thx for the quick answer!
    For my Player object I only wrote a little movement script and use the sprite script of the Othello Framework and unity character controller for player physics. I never had to reference to them before can you tell me how to do it?.
    Can I just write, if my scripts name is “Movement” : Movement mov = gameObject
    .FindGameObjectWithTag(“Player”)
    how does it look when i have to reference to more then on script. And at least what does your Bunny script controle?

    Hope i am not bothering you with my stupid questions 🙂

    kind regards

    1. Since your movement script probably doesn’t include player health management, you would probably want to use something simpler like the following:

          public void RespawnPlayer() {
            var playerTransform = GameObject
               .FindGameObjectWithTag("Player")
               .transform;
      
            // Determine default respawn point automatically?
            if (defaultRespawnPoint == null)
               defaultRespawnPoint = transform
                  .GetComponentInChildren<RespawnPoint>();
       
            // Reposition player
            playerTransform.position = defaultRespawnPoint.transform.position;
         }
  4. thx a lot. the reference error is gone. no health management i didnt try :). Do I understand it right, that this references to the RespawnPoint Script above. Do i have, to attach this to the player then, although? or the RespawnPoint (empty)Object itself?

  5. Ah ok, i see now, i forgot to attach the Respawn Point empty Object to the RespawnPoint script( if this is right)… now the respawn works 🙂 But i get still en reference error….
    NullReferenceException: Object reference not set to an instance of an object
    RespawnPoint.OnTriggerEnter (UnityEngine.Collider collider) (at Assets/Scripts/RespawnPoint.cs:28)

    could you imagine what i did wrong?

  6. At least, I didnt realy edit it. I am not sure, if i set it up right in relation to the Objects and the FallDetectorDeathZone script.

    1. It looks like the game object for your respawn point has not been added as an immediate child of your fall detector death zone object:

      “FallDetectorDeathZone”
      |—> “Respawn Point”

  7. Yes. Respawn Point was still Child of my “Fall Detector” as parent empty object. Refrence error is gone 🙂 thx a lot for your help! And now i can do it all again : Unity just released native 2d Support 😀

  8. Ah one thing: I have an wav file attached, for a little falling sound.So i see its declared in the script but, i think never used…or should it play cause its a special datatype?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s