Examples
This section showcases working setups using the Ledge System.
Use these examples as a reference when integrating the system into your own project.
Sample Character
The SampleCharacter prefab demonstrates a complete working implementation.
It includes:
- Ledge detection
- Movement along ledges
- Climbing up
- Dropping
- Jumping away (Braced Only)
- Hopping up (Braced Only)
Braced vs Free
- A braced ledge position is when the player model can brace its feet on the wall of the ledge

- A free ledge position is when the player model is fully hanging and is holding itself up only by its hands

Demo Scene Overview
The demo scenes is set up to test different ledge scenarios.
It includes:
- Straight ledges
- Inner corners
- Outer corners
- Varying heights
Basic Setup Flow
To quickly test the system:
- Add the
SampleCharacterto your scene - Ensure ledge surfaces are on the correct layer
- Press Play
- Approach a ledge while airborne
You should see the character snap to a valid ledge.
Movement Modules
Detect Ledge
The player should be airborne when detecting ledges.
We use a two ray system to detect potential ledges.
one miss check and one hit check. (in the video below, the red line is our miss check and the blue line is the hit check)
Detect Ledge Move Details
DetectLedgeMoveis aBaseLedgeMovementcomponent.- When the miss check misses and hit check hits, it asks
LedgeHandlerto give a ledge position. - Information of the ledge is sent to ledge agent by calling
LedgeAgent.EnableLedgeGrab LedgeAgentsets the ledge information and restricts movement so the movement is handled by the ledge movements.
If you want to customize this behaviour, we recommend starting with LedgeAgent.EnableLedgeGrab.
You can then modify the DetectLedgeMove if you want it to be working in a different way. The two-ray hit/miss approach has proven reliable across a wide range of geometry configurations.
Remember all you need to provide for the LedgeHandler to calculate a CharatcerLedge is an initial hit point close to the ledge edge and it's normal.
Move Along Ledge
The player can move sideways across connected ledges. It handles curves, inclines and declines.
Move Along Ledge Details
OnLedgeMoveis aBaseLedgeMovementcomponent that listens to player input.- When input is received, it asks
LedgeHandlerto give updated ledge position based on the movement direction - Information of old and new ledge positions are sent to
LedgeAgent LedgeAgentcreatesMoveRequestsand passes them toPlayerLedgeMoveRequestProcessorPlayerLedgeMoveRequestProcessorhandles movements and provides updated positions via event callbacks- The example player controller and animation system use the positions provided by
PlayerLedgeMoveRequestProcessorto handle IK and animations.
If you want to customize this behaviour, we recommend starting with how LedgeAgent.MoveOnLedge creates the MoveRequests and how PlayerLedgeMoveRequestProcessor processes them.
Climb Up
When a ledge is climbable, the player can move up over it.
Climb Up Details
JumpClimbLedgeis aBaseLedgeMovementcomponent that listens to player input.- If the ledge is climbable, it asks
LedgeAgentto move the player up the ledge and run the associated animations. - Some movements are controlled by animation root motion. Climb is one of them.
AnimationRootMotionProxydetects the climb animation applies root motion (viaLedgeAnimationData)- When the animation is done, the player object is pushed the target climb position (
TargetLocation) - Ledge info is flushed and the character is back in the normal state where it can detect new ledges.
If you want to customize this behaviour, we recommend starting with how the LedgeAgent.EnableAutoLedgeClimb and AnimationRootMotionProxy are handling movement and creating the TargetLocation.
Drop From Ledge
The player can release and fall from the ledge. If there is any potential ledge below, the agent tries to grab it.
Drop From Ledge Details
DropFromLedgeis aBaseLedgeMovementcomponent that listens to player input.DropFromLedgechecks if there is any potential ledge bellow the player capsule.- If there are any potential ledges, then the potential initial hit point and a potential hit normal is calculated
- If not, then nothing is calculated.
LedgeAgent.DisableLedgeGrabAndDropis called.- if potential ledge data is provied,
LedgeHandler.LandOnLedgeis called for the player to snap back onto the ledge. - if not, after a short delay ledge info is flushed and the character is back in the normal state where it can detect new ledges.
If you want to customize this behaviour, we recommend starting with the LedgeAgent.DisableLedgeGrabAndDrop.
Jump Away (Braced Only)
The player can jump away from the ledge and rotate 180 degrees. If a potential ledge is behind the player object, the agent tries to grab it.
Jump Away Details
JumpClimbLedgeis aBaseLedgeMovementcomponent that listens to player input.- If the input is pointing at the back of the agent and jump is requested.
JumpClimbLedgechecks if there is any potential ledge behind the player capsule.- If there are any potential ledges, then the potential initial hit point and a potential hit normal is calculated
- If not, then nothing is calculated.
LedgeAgent.DisableLedgeGrabAndJumpAwayis called- if potential ledge data is provied,
LedgeHandler.LandOnLedgeis called for the player to snap back onto the ledge when the player character has done a full rotation to face the ledge. - if not, we wait until the player character has done a full rotation to face the ledge, then ledge info is flushed and the character is back in the normal state where it can detect new ledges.
If you want to customize this behaviour, we recommend starting with the LedgeAgent.DisableLedgeGrabAndJumpAway.
Hop Up (Braced Only)
The player can jump up from one ledge to either a jumping up aniamtion. If a potential ledge is above the player object, the agent tries to grab it.
Hop Up Details
JumpClimbLedgeis aBaseLedgeMovementcomponent that listens to player input.- if the ledge is not climbale we process a hop up instead of a climb
JumpClimbLedgechecks if there is any potential ledge above the player capsule.- If there are any potential ledges, then the potential initial hit point and a potential hit normal is calculated.
- If not, then nothing is calculated.
LedgeAgent.DisableLedgeGrabAndJumpUpis called- if potential ledge data is provied,
LedgeHandler.LandOnLedgeis called for the player to snap back onto the ledge. - if not, after a short delay ledge info is flushed and the character is back in the normal state where it can detect new ledges.
If you want to customize this behaviour, we recommend starting with the LedgeAgent.MoveUpOnLedge and LedgeAgent.DisableLedgeGrabAndJumpUp.
Animations
LedgeAnimationData
This is an ScriptableObject that refereces an animmation state in the animation state machine.
- It specifies if this animation should apply root motion.
- It specifies if this animation should start or stop IK.
- Some timing variables.
AnimationRootMotionProxy
This is a MonoBehaviour that has a reference to a list of LedgeAnimationData and checks:
- If the currently running animation is part of the defined list of
LedgeAnimationData - If so, then it checks if the
LedgeAnimationDataapplies root motion, and if so, takes control of position update from theIAnimationRootMotionConsumer(in this case ourPlayerController) - It checks if the IK should be anbled/disabled and if so makes sure the IK is enabled/disabled at the right time.
Customizing the Examples
The example setup is fully modular.
You can:
- Replace movement components
- Modify detection settings
- Integrate your own character controller
- Swap animation / IK systems
Recommended Next Steps
- Review Runtime Components to understand how the example is built
- Explore Core System to understand the underlying logic
- Start replacing parts with your own implementation