CharacterBody2D wall-cling / wall-walk system

Godot Version

4.5.stable

Question

hi everyone!
i’m working on a wall-cling / wall-walk movement system using a CharacterBody2D, and i’m running into stability problems that I haven’t been able to solve cleanly yet

the goal is for the character to stick to surfaces on demand and, while attached, the character should

  • move along the surface with variable speed
  • have gravity redirected to the surface normal
  • work primarily with flat 90-degree walls, but ideally be robust enough to support any angle

the character can exit this mode at any time and return to classic downward gravity and standard horizontal movement, all handled using move_and_slide()

to detect surface normals, I’m currently using multiple raycasts

  • from the center toward the character’s back “feet”
  • downward to detect the ground
  • forward to detect walls to climb

there is a defined priority order for normal selection (front wall normal → back floor normal → current floor normal). i’ve also tried snapping the character to surfaces before or during rotation

but the collision shape can penetrate walls during rotation, the character can enter infinite rotation loops at corners or edges, the overall system feels fragile, and in some cases the character can “fly off” surfaces

i’m currently trying to rethink the system from scratch, and I’d really appreciate any guidance or high-level advice on how to build a stable and robust surface-adhesion system for a CharacterBody2D. Even conceptual explanations or common patterns would already help a lot!

if I missed any important details, feel free to ask and I’ll clarify
thank you in advance!

Take a look at Area2D. You can set a gravity override value on them. If you code your player to use get_gravity() it will automatically pickup any gravity changes added to an Area2D. All your Raycast2D nodes go away. The only thing you will have to do is deal with rotating the character so “down” faces the gravity vector.

Then you can add an Area2D around each surface you want to change and turn the gravity on/off when the player presses a button. Or, you can get super fancy and have one Area2D that covers the map and just changes which way the gravity is pointing when the player turns it on, based on their location to the closest object.

If you’re using a TileMapLayer, you can store the rotation and/or gravity vector in the tiles. Otherwise you can get super fancy and use edge detection of Sprite2D objects to determine the gravity normal.

To clarify, you would use override gravity for this, so turning it off would reassert normal gravity.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.