Walking on Walls and Ceilings

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By LBfnIPkwfOqJ21hGSoTB

Working on a game where player can attach to walls, floors, and ceilings like a gecko. I’ve been trying to use move_and_slide with an Area2D next to each surface tile to change gravity. But it’s been tricky to get aligned and working and I’m afraid of the character disconnecting or the gravity impacting other objects.

How can I get the player character aligned to the different surfaces and moving along them reliably? Is there a simpler way?

:bust_in_silhouette: Reply From: MysteryGM

Use Kenimatic body, use move and collide.

There is a few ways to do this, but you will have some pains in Godot because it doesn’t use quaternions.

First way, switch Gravity.
This is the simplest way and Godot’s Area nodes actually have properties to do this.

extends KinematicBody

export var GravityDirection = Vector3.DOWN
var GravityStrength = 9.8

func _physics_process(delta):
	var Gravity = GravityStrength * GravityDirection
	#Your character movement goes into velocity
	var Velocity = Gravity * delta
	move_and_collide(Velocity)

How can I get the player character aligned to the different surfaces and moving along them reliably?

The Godot manual shows a tutorial for using move_and_collide() to mimic move and slide: Physics introduction — Godot Engine (3.0) documentation in English

As for using it in your game, you will get the collision from move_and_collide().

extends KinematicBody

export var GravityDirection = Vector3.DOWN
var GravityStrength = 9.8

func _physics_process(delta):
	var Gravity = GravityStrength * GravityDirection
	#Your character movement goes into velocity
	var Velocity = Gravity * delta
	
	var Collision = move_and_collide(Velocity)
	
	if Collision :
		self.GravityDirection = -Collision.normal

This is the basics, it just works with the gravity, everything else is up to you.

1 Like
:bust_in_silhouette: Reply From: Zylann

For some reference, I got a similar mechanic to work in my game:, considering it’s 2D: https://www.youtube.com/watch?v=oyosstz_-4E

Walking on walls involves movement code that ignores gravity, so it’s a bit like platforming without the jumps. In fact, for me gravity ended up being a special case that I implemented as a separate movement state.

To detect walls I basically use a bunch of raycasts or intersection queries, and keep track of what directions the feet and forward vectors of the characters are. Knowing them in addition to jump direction also allows to decide how to position the character when it hits a surface. Then detecting a surface is done either with move_and_collider/slide or more raycasts.

This is a private-source project so I can’t share code, but basically to move along the surface I advance the feet position by one frame, then raycast down from a small distance above (whatever “down” is relative to the surface, it’s important to know). If I get a hit, I snap the feet there and reorient the character according to the hit normal. If I don’t get a hit, there are several possibilities: either I dropped a sharp edge, in that case I either stop, or switch to gravity fall. Or, I hit a sharp wall. In the latter case, a raycast forward can help find back the surface. However I intentionally design my levels to avoid annoying cases like these :stuck_out_tongue:
This video shows some debug visualisation: https://www.youtube.com/watch?v=1_Yi_vf6m9A
I had to face a lot more special cases but I don’t remember them all right now, but one useful thing was to encapsulate “surface following” logic into a SurfaceTracker class, so I could easily focus on it and test it. My game has only one, but if your gecko has 4 feet you could use 2 or 4 SurfaceTrackers for each feet, depends on your game^^

Note that this was for a game where colliders can have arbitrary shapes (round turns, diagonals etc). If your game looks more like just blocks, you could also roll your own simplified collision code by using the tile grid.