Day 92 — Creating a Modular Ledge Climb System
Hey and welcome!
So in the past couple of articles I showed you how to implement a ledge grab and climb mechanic which is working pretty well for us. There is one slight issue with it though. If you create a copy of the platforms and ledges and try to grab and climb your new platforms you’ll come across this problem:
We’ve been teleported to the first ledge! The reason for this is because we’ve set specific values for the _handPos and _standPos that our code is using so it puts us back to the first platform when we collide with our new ledge. We could update the values manually for our new ledge but if we’re creating a lot of these that’s not really something we can do since it would be too time consuming.
The end goal here is to have a prefab ledge grabbing platform that we can add wherever we want and the player can grab and climb up without having to edit in or hard code in position values each time.
To do this we’re going to take advantage of local positions while parented to another object. In the past when we’ve been parenting objects you’ll have noticed that we zero out the position so that the x, y and z values of the child object are 0 which centers it over the parent object. That’s us updating the local position of the child object in relation to its parent object.
The plan here is that when the player is in the ledge grab/climb up animations we’re going to parent them to the ledge checker object we have and set the local positions for the handPos and standPos here.
First things first we need to get the local position values from our current ledge grab and climb up, go ahead and edit your code in your Ledge script:
private void OnTriggerEnter(Collider other)
{
if (other.tag == "Ledge_Grabber")
{
Player playerController = other.transform.parent.GetComponent<Player>(); if (playerController != null)
{
playerController.transform.parent = this.transform;
playerController.GrabLedge(_handPos, this);
}
else
{
Debug.LogError("Can't find Player script");
}
}
}
I’ve highlighted in bold the line you need. It’s pretty important that you parent the player before we run the GrabLedge() method. With this done go ahead and run the game and do a ledge grab + climb up and copy the x, y and z values from both positions over to the handPos and standPos values in your Ledge script component for your ledge checker object.
These are the local values that we’re after. If you run the code now however you’ll notice that it doesn’t do what you’re after just yet.
We need to update the Player script to let the code know to use local positions now:
public void GrabLedge(Vector3 handPos, Ledge currentLedge)
{
_controller.enabled = false;
_anim.SetBool("LedgeGrab", true);
_anim.SetFloat("Speed", 0.0f);
_anim.SetBool("Jumping", false);
_onLedge = true;
_activeLedge = currentLedge; transform.localPosition = handPos;
}public void ClimbUpComplete()
{
transform.localPosition = _activeLedge.GetStandPos();
_anim.SetBool("LedgeGrab", false);
_onLedge = false;
_controller.enabled = true; this.transform.parent = null;
}
As you can see here, that’s nice and easy to do! Instead of the usual transform.position we’re now using transform.localPosition. We also assign the parent of the player object to null which is how we un-parent it from the ledge.
With that done you now have a platform prefab that’s ready to accept an accurate ledge grab and climb up right out the box!