The following blog post, unless otherwise noted, was written by a member of Gamasutras community.

The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.

*This blog post has been written by Alex, our lead programmer. You can read his original post on our website.

You can follow up with all the posts from the series :

The Making of Toto Temple Deluxe: Platforming (Part 1)

The Making of Toto Temple Deluxe: Platforming (Part 2)

The Making of Toto Temple Deluxe: Collisions for Platforming

The Making of Toto Temple Deluxe: The Unique Experience

Collision/Physics engine in unity have been a blessing, but it has it’s fair share of flaws when trying to adapt it to a fast paced platformer, now we will talk about these and the workarounds to get near perfect collision detection.

Collider for each task.

The character must have several collision zones, each has its use: one attack hit box, one weak hit box (to receive the attacks) and one physical collider. This gives the dev much needed control over how threats/collectibles/events/enhancements/enemy weak points interact with the main characters.

Usually, we like to make the main characters weak collision smaller than his physical collision, so there are more “holy fetuccini, that was close!” moments and less “But I wasn’t even touching it!” moments.

Inversely, we like to make the main characters attack collisions a little bigger, so if there is visual ambiguity, the game will cooperate with the will of the player.

Here is a toto at rest, let’s study its anatomy.

In Unity, there can be only one collider per entity, so we must put the other colliders inside the character, and reference the character to those colliders through a simple home-made mediator system.

void Awake () { _master = ( ICollidable )master; } void OnTriggerEnter( Collider other) { if (receiveSignal) { ColliderContainer otherCol = other.GetComponent< ColliderContainer >(); if (otherCol == null ) { _master.enterCollision(other.gameObject, LayerMask .LayerToName(other.gameObject.layer), other.bounds); } else if (otherCol.master!= master) { _master.enterCollision(otherCol.master.gameObject, LayerMask .LayerToName(other.gameObject.layer), other.bounds); } } }

Collisions need polish.

According to my understanding of unity collision/physics engine, PhysX, my characters overlap with the level colliders for a frame before beign replaced at the correct place, this leads to a really cheap feeling and some errors in the interpretation of collisions at high speeds.

Interpenetration (overlap) is a plague we must act against!

This leads me to make a function called “PreventCheapInterpenetrating” which is executed after the movement of the character is done and before any physical calculation, that checks if the player will touch something over it’s course in the next frame, if yes, it reduces the character’s velocity so it just gently touches the surface instead of ramming into it, this way, physics calculations to determine the position of the character afterward are more accurate and the brief overlap is not visible anymore.

Slow down before your collision, little toto!

Now that we prepare for impact, we must properly analyse the impact; do I touch a ground, a wall, a ceiling, what angle is it? Sadly, the native collision interpretation can be strange sometimes, giving contact points that are out of both the receiving and the colliding collider, with surface informations that are impossible. For example, if I land on the ground, the collision points could be higher than the ground, way off at the right, and the angle of the collision would be in diagonal.

I cannot use the collision points, happily there is a function called ClosestPointOnBounds, that returns the bounds of a collision (extreme values forming a box around the collider, not the actual closest point in the collider itself). I need to know without a doubt the nature and angle of the surface I hit, how do I do it? I know that all my characters will have square physical colliders and won’t ever rotate, so I can use character.ClosestPointOnBounds(collider.center). Then cast a ray between that point and the center of the collider, with regular shapes it should always give the good surface you hit.

Here is the code needed to do so:

protected Vector3 GetNormalOfHit( Collider collider) { Vector3 rayDestination = collider.bounds.center; Vector3 rayOrigin = col.ClosestPointOnBounds(rayDestination); Vector3 rayDiff = rayDestination - rayOrigin; rayOrigin -= rayDiff.normalized * 5 ; rayDiff = rayDestination - rayOrigin; ray.origin = rayOrigin; ray.direction = rayDiff.normalized; RaycastHit hit; if (rayDiff.magnitude > 0 ) { collider.Raycast(ray, out hit, rayDiff.magnitude + 2f ); return hit.normal; } return new Vector3(); }

If you did not understand a word said in the previous paragraph, this picture should be of help.

Colliding opinions!

In Rogue Legacy, there are times when you get hit by projectiles that are under a platform when you land on it, because at some point in the code, your downward speed made you pass through the platform before beign placed back to the top of it.

Still in Rogue Legacy, there are relatively rare incidences of neighbooring collision issues, but all in all, it’s a game that kept me going for a long time despite the crudeness of its platforming!

In Conclusion

Navigation is important, and it needs some tweaking, but collisions must be perfect in order for navigation to be efficient, so there goes the importance of colliding well! In this post I presented you some ways to overcome some lacks in the collision engine. If you ever want some specific details, don’t be shy! Next time we’ll talk about the design decisions behind the original idea of Toto Temple, so stay tuned!