A powerful 3D/2.5D game controller plugin for Bevy Engine.
The Ladder System provides structured vertical movement mechanics, allowing players to mount, climb, and dismount defined ladder objects. Unlike the free-form Climb System, ladders offer constrained axis movement and specific interaction states.
The system operates on a “Constraint” basis. When a player interacts with a ladder, their physics control is overridden. Gravity is disabled, and input vectors are remapped to slide the character along the ladder’s local Up/Right vectors.
The system intelligently handles camera-relative inputs.
This is managed by comparing the camera’s forward vector with the ladder’s up vector (ladder_angle). If the angle exceeds min_angle_to_inverse_direction (typically 100 degrees), the input sign is flipped.
LadderMovementState)None: Normal gameplay.Approaching: Moving to engagement distance.Mounting: Locked animation entering the ladder.ClimbingUp/Down: Active user control.Dismounting: Locked animation exiting the ladder.LadderSystem (The Object)Attached to the ladder entity in the world.
| Field | Type | Default | Description |
|---|---|---|---|
tag_to_check |
String |
"Player" |
Only entities with this Tag can use this ladder. |
use_ladder_horizontal_movement |
bool |
true |
Allows A/D shimmying. |
move_in_ladder_center |
bool |
false |
Forces player X-axis to lock to center. |
gizmo_color |
Color |
Red |
Debug line visualization. |
PlayerLadderSystem (The Player)Attached to the character controller.
| Field | Type | Default | Description |
|---|---|---|---|
ladder_movement_speed |
f32 |
5.0 |
Base climb velocity. |
min_angle_to_inverse_direction |
f32 |
100.0 |
Angle threshold for reversing Up/Down inputs. |
ladder_found |
bool |
false |
Runtime flag (ReadOnly). |
LadderMovementTracks real-time inputs and velocity application.
vertical_movement_amount: Multiplier for Y-axis speed (0.3).horizontal_movement_amount: Multiplier for X-axis speed (0.1).Mounting is a critical phase where control is taken away to align the character.
LadderMovementState::Mounting.gravity_scale or sets zero_gravity_mode = true.transform.position to ladder.position + offset.Occurs when:
LadderExitDetection raycasts hit nothing (top) or floor (bottom).The system calculates a dismount_target_position (e.g., 0.5 units behind the player) and lerps them there before re-enabling gravity.
If use_ladder_horizontal_movement is enabled, ‘A’ and ‘D’ keys move the player along the ladder’s local Right vector.
LadderSystem component.LadderDirection component (defines which way is “Up”).Collider (Sensor) for detection.commands.spawn((
Transform::from_xyz(0.0, 5.0, 0.0),
LadderSystem {
use_ladder_horizontal_movement: false,
..default()
},
LadderDirection::default(),
Collider::cuboid(0.5, 5.0, 0.5), // Needs to be a Trigger/Sensor
Sensor,
));
Must have PlayerLadderSystem and LadderExitDetection.
commands.spawn((
// ... CharacterController ...
PlayerLadderSystem {
ladder_movement_speed: 4.0,
..default()
},
LadderMovement::default(),
LadderMovementTracker::default(),
LadderAnimation::default(),
LadderExitDetection::default(), // Crucial for not climbing forever
));
Cause: The LadderDirection vector on the ladder entity is inverted.
Fix: Rotate the ladder entity 180 degrees or manually set LadderDirection.direction = Vec3::NEG_Y (rare).
Cause: No collision trigger or tag_to_check mismatch.
Fix: Ensure the ladder has a Sensor collider and the Player has a Name or Tag matching ladder.tag_to_check.
Cause: min_angle_to_inverse_direction might be too sensitive or camera forward vector is misaligned.
Fix: Increase the angle to 120.0 or debug draw the ladder_angle to see what the system thinks the view alignment is.