2.5D Platformer — Improving the Ledge Grab #10
How’s it hanging?
In my previous article, I tried implementing a Ledge Grab feature for the first time, and it was okay-ish. It worked fine, but I didn’t like the idea of adding invisible triggers everywhere to make this work. It didn’t feel all that clean, and so, I went ahead and changed the previous method to Raycast detection. Was it worth it? Keep reading to find out!
Let’s backtrack a bit
If you didn’t read that article, it’s fine. I’ll explain again what the Ledge Grab was supossed to be.
Character Controllers don’t exactly know what a ledge is, or when it should perform a ledge grab. It is up to you to define those things before you try coding it.
For me, a ledge can be any climbable surface as long as the controller is close enough to those surfaces, and the controller should perform a ledge grab if the Ledge Raycasts have made contact with them.
The difference between the invisible trigger and the Raycast methods is just the way the controller detects a ledge in its surroundings. One is easier to set up, but the other one doesn’t require invisible triggers in every single prefab.
Instead of checking for a ledge trigger with another trigger like this:
I do that with a raycast:
First of all, the Ledge Grab check is called every frame (Update()) as FixedUpdate doesn’t detect the ledges as consistent as I would like it to. To avoid messing up the optimization, this check is only called when airborne.
To start checking for any ledges, I begin by casting a vertical raycast in front of the controller (only in the direction the controller is facing), and just above the controller’s max Y bounds. Both axis have a small offset to properly fit with the Ledge Grab animation.
If the vertical raycast has detected a collider / surface, it needs to make sure that it’s close enough to that surface with another horizontal raycast. Again, the raycast is casted right in the direction the controller is facing.
And if the horizontal raycast has hit another collider, then it confirms that the controller is near a ledge and triggers the Ledge Grab behaviour.
And by using the position of the raycast hit points, I move the position of the controller to an approximate and ideal point in the LedgeGrab method.
I’d say this is far more consistent and cleaner than the invisible trigger method to detect ledges. Even if the raycast detects early or late a collider, it can always be solved by doing some calculations with the raycast hit points and the lenght and offsets of both raycasts.
What I can say I like about the Invisible Trigger method is that you basically avoid any weird positioning errors by manually setting a position for the controller. But is it worth it, to put invisible triggers in every single one of your platforms? It all depends on the scope of your project. But for me, I will try to go for one that will be flexible enough to expand or modify.