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.
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).
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 |
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.
Are you using RigidBody2D at all in your platformer? Or do you just use BoxColliders and handle collision and separation yourself?
ReplyDeleteI'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.
DeleteI've added it to my game, working very well so far. thanks Nic.
ReplyDeleteI 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?
ReplyDeletePhysics.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