Implementing Ladder Climbing Animation in Unity 2021
In this article we’ll give the player character the ability to climb up ladders!
The Ladder Prefab
The ladder prefab is where it all starts.
While there is a non-trigger collider for the actual dimensions of the ladder, there are 3 trigger type colliders.
One for the top, middle, and bottom of the ladder.
This will allow us to detect where the player’s character has entered the ladder from and react accordingly.
There are also four child game objects that hold positional data for later comparison.
These include where the player should snap to the ladder when entering from the top or bottom, and where the player will be have finished climbing the ladder depending on which direction the player is moving in (up/down).
The ladder class/script also has a setting to describe whether the ladder is angled from the top left to the bottom right or vice versa so that we can code in the player’s character to face the correction direction when getting on and off the ladder.
The ladder class/script predominantly holds information related to each instanced ladder game object.
It does also create some public enums for use here and elsewhere and public methods to return the information it stores.
The PlayerAnimations class/script is responsible for implementing and holding the player’s character animation state.
Every parameter in the Animator for PlayerChar_Anim_Controller has a corresponding value in the PlayerCharAnimState enum declared here.
We also have an enum that makes it easy to track which direction the character is facing.
PlayerController Class/Script — Class Variables
The PlayerController class/script is responsible for all player character related physics and input.
It also needs to tightly integrate with the PlayerAnimations class/script to sync the player’s input and character physics with the character animations.
Due to the size, complexity, and importance of this script, I’ve taken the time to really organize the class variables and even added tooltip descriptions.
I might know off-hand what everything does right now, but it’s likely I won’t months down the road.
Because this script has undergone such an exhaustive refactoring during the process of adding the ladder mechanics, I will be showcasing it in its entirety.
Coming at just shy of 400 lines, but here we are.
Alright, let’s go over the ladder logic specifically.
The OnTriggerEnter() method is a good place to start since this will be triggered when the player character enters a trigger collider like those we have on the ladder.
Here we check the other game object’s tag and whether the _isClimbingLedge Boolean flag is active.
Then we call the workhorse method for the ladder logic, the ClimbLadder() method.
This method will start by pulling in the object collider that was triggered and getting all of the information from that instance of ladder.
It also determines if the player’s character is triggering the collider at the top of the ladder, in the middle, or at the bottom of the ladder.
If in the middle, we trigger the “Ladder Dropping” animation state to slide down to the bottom collider and then climb the ladder.
We can see the slide down mechanic when hitting the middle collider shown above.
As the ClimbLadder() method continues, it determines which way the character should be facing based on the ladder angle.
We then assign some class variables for the current snap to position on the ladder, reached end of climbing position on the ladder, and moving on ladder direction.
Then we disable the player’s ability to move the character and set the animation state to “Ladder Climbing Up” or “Ladder Climbing Down”.
The Boolean flag _moveTowardsSnapTo is set to True so that FixedUpdate() can execute the movement in the physics loop.
Lastly, it calls the ResetPlayerSnapTo() coroutine which will reset the _moveTowardsLadderSnapTo Boolean flag to false and set _isClimbingLadder Boolean flag to true to also be triggered in the FixedUpdate() method which has at this point completed moving the player to the snap to location on the ladder.
This method uses a simple Vector3.MoveTowards to quickly snap the player to the ladder at the given position.
The game designer can modify the speed of snapping to in the inspector with _snapToMoveSpeed.
This method handles the physics and some related animation called to the PlayerAnimations class to moving the character up or down the ladder.
Once it reaches the designated end position for either climbing down or up, it triggers the correct animation for either climbing up to the top or dropping down to the ground.
It then calls EnableMovement() with a delay to avoid the player gaining control before animations have completed.
Lastly it makes sure the character is facing the correct direction after exiting the ladder.
This coroutine handles both when the character is hanging from a ledge and climbs up as well as when the character climbs up the top of a ladder.
That’s why it requires two Booleans to determine which scenario is in effect.
Except, that by the time I was done, my code logic worked in both circumstances without needed to know which.
So this is just vestigial code at this point.
It could be removed, but it may be necessary in the future so I’ll leave it for the time being.
The trick to syncing up the player character position with the animation’s position is _playerAnimations.GetAnimator().bodyPosition.
We can see this occurring above when the character controller collider is still on the ladder while the character animation climbs up the ledge.
Due to this method of syncing, we need to use coroutines effectively based on animation lengths and speeds and set all transitional durations for the animation transitions in the Animator window to 0, no delay.
Once this sequence has completed, we EnableMovement() and the player takes over again.
And since we are sharing code with climbing up a ledge, why don’t I showcase a gif of that as well.
The event subscribers shown above handle the dropping or climbing up from a ledge.
This method may or may not be necessary but it hasn’t been harmful.
I believe it improves the syncing of player position to animator position.
And that’s it for me folks, that’s everything I’ve got on this.
ADDENDUM: Boolean flag to prevent player from immediately climbing back up ladder.
This will make sure the player cannot climb the ladder again until it has exited a ladder trigger.