Friday, March 7, 2014

Addendum: 2D Platformer Collision Detection in Unity

NOTE: Please see Yet Another Addendum to this solution for important bug fixes. 


This is an addendum to my original post, 2D Platformer Collision Detection in Unity. The solution explained in that post was a great "start", but ultimately had problems which I'd like to go over and correct in this post, so that I don't lead anyone too astray!

The Problem

To summarize, entities could fall through collision layers under the right conditions. The most notable use case was corner collisions at low framerates (< 30FPS). 


In the picture above, the white lines represent the raycasts. The green box is the box collider. As you can see, that small corner gap is enough to cause the player to slip through the collision layer. As noted before, this issue was highly prevalent when the frame rate was < 30FPS (I capped the frame rate using a small script to take into consideration people with slower hardware). For the more astute Unity users, I can hear the screams of "FixedUpdate! FixedUpdate!" Just trust me that using FixedUpdate had no effect on this issue. I tried, in several different manners, and all resulted in the same problem.

The Solution

Originally, the rays were being casted from the edges of the box colliders instead from within the box collider. Why is this important? I'm going to borrow a diagram from Yoann's Pignole Gamasutra article.

Source: Gamasutra: The hobbyist coder #1: 2D platformer controller by Yoann Pignole
This makes sense, but why would I only have an issue at slow frame rates? To be honest, I still don't know. I'm guessing it had to do with the speed in which raycasts were executed (which you would think calling within FixedUpdate would fix, but didn't). 

Ultimately, I rewrote the system completely, ensuring the rays were casted from the center of the box collider, and when resolving the collisions, moving the entity to the point of collision. This solution completely removed all issues I noticed. 

This provides a much cleaner, robust solution. I can also more easily adjust the number of rays I cast, as well as allowing to cast the rays outside of a margin, if need be.















5 comments:

  1. Are you using RigidBody2D at all in your platformer? Or do you just use BoxColliders and handle collision and separation yourself?

    ReplyDelete
    Replies
    1. I'm not using any of the 2D physics stuff; it wasn't available when I started. For the players, I use BoxColliders and handle all collision and separation as documented. Some objects I will just let the physics engine take care of, however.

      Delete
  2. I've added it to my game, working very well so far. thanks Nic.

    ReplyDelete
  3. I see lots of implementations using ray casts. Why not box casts in the direction of the players velocity? Am I missing something by using that approach?

    ReplyDelete
    Replies
    1. Physics.BoxCast wasn't added to the Unity API until 5.3, so it's a very new method. I'd be interested in seeing how that works in comparison.

      Delete