How to make the character face the plane you are climbing on?

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

When player climbs on a wall, the forward direction may not be perpendicular to the wall plane, which will result in weired animation. I want adjust the character’s rotation at the moment FSM changes to climb state. I tried a few ways but none of them works including:

  1. change the basis.z with -1 * collision normal

  2. look at the collision point (I know why this fails because if the forward direction is not perpendicular to the wall the look_at won’t work. If it is perpendicular there’s no need to look at)

I’m new here and a newbie to gamedev. I’m very grateful if you are willing to offer some help.

this works perfect when climbing on a cube whose faces are not bevel.

What about bevel cases where the y component is no longer Vector3.UP

godotlearner | 2022-04-11 18:08

:bust_in_silhouette: Reply From: lewis glasgow

using this function it returns a new transform

func align_with_y(xform, new_y):
    xform.basis.y = new_y
    xform.basis.x = -xform.basis.z.cross(new_y)
    xform.basis = xform.basis.orthonormalized()
    return xform

xfrom is the current transform and new_y is the normal (i suggest using a raycast normal) you want to be oriented at

global_transform = align_with_y(global_transform, $raycast.get_collision_normal())

It turns out to be this:

before hit the wall:

after hit the wall:

Here is how I use this snippet:

func activated(_message := {}) -> void:
	var normal = character.climber.get_chest_collision_normal()
	var global_transform = character.rotation_helper.global_transform
	character.rotation_helper.global_transform = align_with_y(global_transform, normal)

func align_with_y(xform, new_y):
	xform.basis.y = new_y
	xform.basis.x = -xform.basis.z.cross(new_y)
	xform.basis = xform.basis.orthonormalized()
	return xform

godotlearner | 2022-04-12 04:55

the only thing i can suggest because your images are not showing is to change

character.rotation_helper.global_transform = align_with_y(global_transform, normal)

to

character.rotation_helper.global_transform = align_with_y(character.rotation_helper.global_transform, normal)

lewis glasgow | 2022-04-17 14:48

:bust_in_silhouette: Reply From: godotlearner

Someone on Reddit gives me the solution, here is the code:

var z = -1 * normal
var x = normal.cross(Vector3.UP).normalized()
var y = z.rotated(x, -PI/2)
character.rotation_helper.transform.basis = Basis(x, y, z)

The point is getting x by z-up plane
and getting y axis by rotating z around x by -90 degree