I have been working on building climbing mechanics for a 3d adventure platformer. Through piecing together from multiple tutorials I was able to get something similar to what I wanted. However when I tried to have the player character climb around on the outside of a corner greater than 90 degrees that is where the issues lie.

One of the issues (and the main one) I ran into is when the player is going around the corner he flips between two normal values, causing the character to 'spaz' out. It isn't that uncommon for the Player to get rotated away from climbable object and just be floating in mid air. I originally thought it was because I was using two separate objects to get the corner, but through testing with a collision ConvexPolygonShape I got the same results.

The other issue is a minor one compared to the previous one. If I have the player climb down at the backside of the climbable object it will occasionally pickup strange normal values. The character then starts to twitch for a little while climbing straight down. Works perfectly find if you're doing it from the front of the object

The way I have it working is that 3 raycasts are used to get the normal position. One at the center, one going 15 degrees to the left, and the last going 15 degrees to the right. I then take the 3 values and Lerp the values down to one variable. That variable is then used to determine the players orientation and facing direction when climbing.

here is code I'm using

in the input (event) function

``````    if player_state == 2:
if event is InputEventMouseMotion:
return climbDir
else:
var Climb_Face_L = lerp(climbCast02.get_collision_normal(), climbCast_C.get_collision_normal(), .5)
var Climb_Face_R = lerp(climbCast01.get_collision_normal(), climbCast_C.get_collision_normal(), .5)
climbDir = lerp(Climb_Face_L, Climb_Face_R, .5)
printt(climbDir.x, climbDir.z)
``````

The Climb process function placed in the physics process

``````func _Climb_process(delta):

climbDir.y = 0
gravity = 0
walk_speed = .75
sprint_speed = 2

var z = -1 * climbDir
var x = climbDir.cross(Vector3.UP).normalized()
var y = z.rotated(x, -PI/2)

character.transform.basis = Basis(x, y, z)
var H_rotation = character.global_transform.basis.get_euler().y

if Input.is_action_pressed("Forward") || Input.is_action_pressed("Back") || Input.is_action_pressed("Left") || Input.is_action_pressed("Right"):
direction = Vector3(Input.get_action_strength("Left") - Input.get_action_strength("Right"),
Input.get_action_strength("Forward") - Input.get_action_strength("Back"),
0)

direction = direction.rotated(Vector3.UP, H_rotation).normalized()
``````

I can provide Images and or more code if needed

Godot version 3.5
in Engine