Fall detection for platform game in Unity

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. Here is the process for setting 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.

    // License: MIT
    using UnityEngine;
    
    public sealed class FallDetectorDeathZone : MonoBehaviour
    {
        // Default respawn point to use
        public RespawnPoint defaultRespawnPoint;
        // Sound to play when falling
        public AudioClip fallSound;
    
    
        private void OnTriggerEnter(Collider collider)
        {
            if (collider.tag == "Player") {
                this.RespawnPlayer();
            }
            else {
                // Destroy whatever has set off trigger
                Destroy(collider.gameObject);
            }
        }
    
        public void RespawnPlayer()
        {
            var bunnyGO = gameObject.FindGameObjectWithTag("Player");
            var bunny = bunnyGO.GetComponent<Bunny>();
    
            // Deduct from player lifes
            bunny.IncurDamage(1, fallSound, true);
    
            // Determine default respawn point automatically?
            if (this.defaultRespawnPoint == null) {
                this.defaultRespawnPoint = transform.GetComponentInChildren<RespawnPoint>();
            }
    
            // Reposition player
            bunny.transform.position = this.defaultRespawnPoint.transform.position;
        }
    
    
        private 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 custom gizmo drawing to make mechanism easier to work in the 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).

    // License: MIT
    using UnityEngine;
    
    // Respawn points are selected when triggered by player
    public sealed class RespawnPoint : MonoBehaviour
    {
        private void OnTriggerEnter(Collider collider)
        {
            if (collider.tag != "Player") {
                return;
            }
        
            // Set as default trigger point
            var detector = this.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!