Maybe this helps, a character controller that uses spherical gravity and rotates its body along the normal. It’s important that you take your current up vector in account, otherwise you get the problems you described.
extends CharacterBody3D
var planet_pos := Vector3.ZERO
const SPEED = 5.0
func _physics_process(delta: float) -> void:
if not is_on_floor():
velocity += up_direction * -10.0 * delta
else:
velocity = Vector3.ZERO
var input_dir := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
var input_rot := Input.get_axis("ui_left", "ui_right")
if input_rot and Input.is_key_pressed(KEY_SHIFT):
global_rotate(up_direction, PI * -0.5 * delta * input_rot)
input_dir = Vector2.ZERO # clear move dir so we don't rotate AND move
var direction := (global_basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
velocity += direction * SPEED
# set the new up vector based on the next position on the planet
var new_up := ((global_position + velocity * delta) - planet_pos).normalized()
var angle := up_direction.angle_to(new_up)
if angle > 0.0:
var axis := up_direction.cross(new_up).normalized()
global_basis = global_basis.rotated(axis, angle)
up_direction = new_up
move_and_slide()
# clear movement velocity after move_and_slide
velocity -= direction * SPEED