> For the complete documentation index, see [llms.txt](https://docs.flatredball.com/flatredball/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.flatredball.com/flatredball/tutorials/platformer-plugin/climbing-ladders.md).

# Climbing Ladders

### Introduction

This walkthrough covers climbing ladders. When climbing a ladder, the platformer Player moves vertically by pressing up or down on the analog stick or d-pad. Ladders and vines give access to areas that jumping alone can't reach.

{% embed url="<https://youtu.be/htFJTiVH5Ao?t=1465>" %}

The sample project can be downloaded from GitHub: <https://github.com/vchelaru/FlatRedBall/tree/NetStandard/Samples/Platformer/LadderDemo>

<figure><img src="/files/WwCxtNl5N8PUYJWZcGaP" alt=""><figcaption></figcaption></figure>

This walkthrough refers to LadderDemo as *this demo* and *the demo*.

### Main Concepts

This walkthrough covers a number of concepts for climbing ladders:

* Defining ladder platformer values to control climbing speed
* Defining ladders in the TMX file
* Telling the player where a ladder's collision is, and where it ends
* Reacting to the player reaching the top or bottom of a ladder

### Climbing Values

The Player entity defines a set of movement values for climbing called **Climbing**.

![](/files/RtWaNhkfYrD7aptOBMww)

While these values are active, the player has direct control over vertical movement - climbing up and down sets the player's Y velocity from the Climbing Speed. Notice that the Player also has a non-zero **Max Speed** under the Horizontal Movement section. This means the player can move horizontally while on the ladder. Some games, like Super Mario World, allow this. Others, like Mega Man X, only allow vertical movement on ladders. This demo allows horizontal movement, but setting Max Speed to 0 removes it.

### Defining Ladders

Ladders are placed in the TMX file as tiles. The following image shows just the GameplayLayer with ladders.

![](/files/rAjuTVEqKG8o6qrzdRXf)

Notice that the ladder tiles define the maximum height that the player can climb.

![](/files/FRZdI0vCJlIAByDk60Sg)

You can add extra climb height by adding more tiles to the map. The GameplayLayer tiles don't need to match the visual layer exactly.

![](/files/T6HzZf0oyb5l6Z8ynGU6)

These ladder tiles use the **Ladder** type.

![](/files/l8epJHD0qpdR4QfgwW7W)

This lets Glue create a **LadderCollision** TileShapeCollection.

![](/files/nKQZ5p5M93IDKUEEYG3p)

### Switching to Climbing Movement

Platformer entities handle ladder climbing automatically: grabbing a ladder, clamping at its top, and falling off if the player steps sideways off of it are all built in. Your code just needs to tell the entity two things: which movement values to use while climbing, and where the ladder collision is.

Assign the **ClimbingMovement** property once, in CustomInitialize:

```csharp
private void CustomInitialize()
{
    ClimbingMovement = PlatformerValuesStatic["Climbing"];
    ...
}
```

That's it for movement values - you never assign GroundMovement or AirMovement to make the player climb. ClimbingMovement is a separate slot, and the platformer entity switches to it on its own once the player grabs a ladder.

Player.cs's CustomActivity only needs to handle the movement values a real project usually wants: switching between Ducking, Running, and Ground while **not** climbing.

```csharp
private void CustomActivity()
{
    animationController.Activity();

    if (CurrentMovementType != MovementType.Climbing)
    {
        if (VerticalInput.Value < 0)
        {
            GroundMovement = PlatformerValuesStatic["Ducking"];
        }
        else if (RunInput.IsDown)
        {
            GroundMovement = PlatformerValuesStatic["Running"];
            AirMovement = PlatformerValuesStatic["RunningAir"];
        }
        else
        {
            GroundMovement = PlatformerValuesStatic["Ground"];
            AirMovement = PlatformerValuesStatic["Air"];
        }
    }
}
```

The `if (CurrentMovementType != MovementType.Climbing)` check keeps this code out of the way while the player is on a ladder. Everything else - grabbing the ladder, letting go, clamping at the top - is handled for you.

### Telling the Player Where the Ladder Is

The platformer entity still needs to know where the ladder collision actually is - that part depends on your level, so it isn't automatic. Every platformer entity has a **LastCollisionLadderRectange** property for this. You set it to the ladder rectangle the player is touching, and set it back to null when the player isn't touching one.

The ladder collision needs to run before other collision, so GameScreen calls it directly instead of letting it run automatically:

```csharp
private void DoCollisionActivity()
{
    // first we reset the collision...
    foreach (var player in PlayerList)
    {
        player.LastCollisionLadderRectange = null;
    }
    // Then we do the collision which sets LastCollisionLadderRectange if a collision happens
    PlayerVsLadderCollision.DoCollisions();
}
```

Whenever a collision happens, LastCollisionLadderRectange is set in GameScreen.Event.cs's OnPlayerVsLadderCollisionCollided:

```csharp
void OnPlayerVsLadderCollisionCollided(Player player, TileShapeCollection ladder)
{
    player.LastCollisionLadderRectange = ladder.LastCollisionAxisAlignedRectangles.First();
}
```

This results in LastCollisionLadderRectange holding a rectangle whenever the player touches a ladder, and null otherwise. Note that this simple version won't behave well if two ladders are placed right next to each other - see the next section for the code the demo actually uses, which also handles ladder height.

### Reacting to Reaching the Top or Bottom

A platformer entity automatically calls two methods you can override in your own code:

* **OnLadderTopReached** - called when the player has climbed as high as the ladder allows and isn't holding Up
* **OnLadderBottomReached** - called when the player is climbing, touches solid ground, and isn't holding Down

Both are optional. You don't need to do anything in them for climbing to work correctly - reaching the top leaves the player hanging there with gravity turned off, and reaching the bottom (or stepping off either side) switches the player back to normal ground/air movement on its own. Use these methods for extra behavior, like playing a sound or triggering an animation:

```csharp
partial void OnLadderTopReached()
{
    // for example: play a "reached the top" sound here
}

partial void OnLadderBottomReached()
{
}
```

### Limiting Ladder Height

A platformer entity has a **TopOfLadderY** property that caps how high the player can climb. You assign it yourself, since only your code knows where the top of a given ladder actually is. The demo assigns it in OnPlayerVsLadderCollisionCollided, by walking up the ladder's tiles one at a time until it finds the last one:

```csharp
void OnPlayerVsLadderCollisionCollided(Player player, TileShapeCollection ladder)
{
    player.LastCollisionLadderRectange = ladder.LastCollisionAxisAlignedRectangles.First();

    var topRectangle = player.LastCollisionLadderRectange;

    var rectangleAbove = ladder.GetRectangleAtPosition(topRectangle.X, topRectangle.Y + ladder.GridSize);

    while (rectangleAbove != null)
    {
        topRectangle = rectangleAbove;
        rectangleAbove = ladder.GetRectangleAtPosition(topRectangle.X, topRectangle.Y + ladder.GridSize);
    }

    player.TopOfLadderY = topRectangle.Top;
}
```

Use `topRectangle.Top` here, not `.Bottom` - `.Top` puts the player's feet at the actual top of the ladder, standing on whatever floor is up there. `.Bottom` stops the player a full tile short, still hanging in the air. The platformer entity clamps slightly inside the top tile automatically, so you don't need to account for that yourself.

### Custom Movement Logic vs. Player Platform Movement Values

Simple games may assign movement values automatically on collision, as shown in the [Adding Ice and Water document](/flatredball/tutorials/platformer-plugin/ground-type-and-water-movement/03-adding-ice-and-water.md), where values are assigned through the FlatRedBall dropdowns on the Collision Relationship. Ladders don't fit that pattern - a ladder isn't something the player collides into and bounces off of, so entering and leaving the climbing state is driven by your own game logic instead. In practice this means assigning ClimbingMovement once and setting LastCollisionLadderRectange from your ladder collision, as shown above.

### Conclusion

This walkthrough covered how to add ladder climbing to a platformer game.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.flatredball.com/flatredball/tutorials/platformer-plugin/climbing-ladders.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
