# Player Movment on Sphere/ Planet

4.2.1

### Question

Hey there,
I am having trouble with my project, where I want to move the player character along a planet surface, so that the the local -y Axis is always oriented towards the planet center. So far I got it working if I move along the local z axis of my player model, but for some reason it does not work when I move along the local x axis, can somebody give me a tip whats wrong with my code?

Thanks!

``````extends RigidBody3D

var move_force = 5
var planet_center = Vector3.ZERO
var gravity_direction

func _physics_process(delta):
move()

func _integrate_forces(state):
gravity_direction = (planet_center - global_transform.origin)
state.transform.basis.y = -gravity_direction

func move():
if Input.is_action_pressed("move_forward"):
apply_force(move_force* transform.basis.z,)
if Input.is_action_pressed("move_back"):
apply_central_force(move_force* -transform.basis.z)
if Input.is_action_pressed("move_left"):
apply_central_force(move_force* transform.basis.x)
if Input.is_action_pressed("move_right"):
apply_central_force(move_force* -transform.basis.x)

``````

Unfortunately I cannot upload any Images/videos as a new user :-/

It may have to do with the fact that youâ€™re not updating the rotation as you walk around. Youâ€™re uhâ€¦ setting the vertical translation of the basis to the negative of the gravity force???

1 Like

I bleev Area nodes can do local gravity. It might help you.

Here is a video to clarify what it currently looks like.

As you can see, when I move in the direction of the local z axis, the player always gets rotated so that local y is pointing â€śupâ€ť
So my idea was (and i think thats the way my code works) : Calculate a vector pointing towards the planet center, I called this vector â€śgravity_directionâ€ť and then simply transform the -y axis so it points towards this vector.

Yes, that is what I am using, I should have mentioned that. There is local gravity from an area3D node around the planet, which pulls the player towards the planet center.

Okay. I have not tried that stuff. Looks like it doesnâ€™t correct the rotation then, so you have to.

This stuff is always, for me, trial and error. I wish Godot placed more value in quality of life for non-mathy devs. There are so many funcs they could provide to just do stuff that would take me months to figure out.

I think to do this correctly you will need Quaternion.
This is because if you use euler angles, you will get into a problem where going near the poles makes movement really confusing.

So for your code, it should look something like thisâ€¦

``````func update_angle():
var vertical: Vector3 = player.position.direction_to(planet.position)
var verticalq: Quaternion = Quaternion.from_euler(Vector3.FORWARD.signed_angle_to(vertical.x, Vector3.RIGHT), Vector3.FORWARD.signed_angle_to(vertical.y, Vector3.UP), Vector3.FORWARD.signed_angle_to(vertical.z, Vector3.FORWARD))
var prev_angleq: Quaternion = player.quaternion
var adjustq: Quaternion = (- prev_angleq) * verticalq
``````

Of course, you can simplify it, I just split it into easier to read steps.

1 Like

Note that if you are moving on a single plane, you could always use a flat surface and distort it using a vertex shader. (You may have to subdivide meshes if they lack detail if the curvature is strong.)

This way, you donâ€™t have to deal with any of the potential physics issues you may encounter when trying to stick to a sphere with gravity. This is how games like Animal Crossing work.

1 Like

Hi, here is what i used to orient my player ( CharacterBody3D ) to the surface of a planet.

This gets the vector of the gravity, that is it gives you the direction the players feet should be facing ,which is the planets surface.

var gravityVec = planet.transform.origin - player.transgorm.origin.normalized()

Then you put this

``````if transform.basis.y.normalized().cross(gravityVec ) != Vector3():
look_at(planet.global_transform.origin, transform.basis.y)
elif transform.basis.x.normalized().cross(gravityVec ) != Vector3():
look_at(planet.global_transform.origin, transform.basis.x)
``````

then for the controls ,

Forward

``````	position -= transform.basis.y * speed
``````

Backward

``````         position += transform.basis.y * speed
``````

you can change position with velocity if you wish.

Turn Left

transform.basis = transform.basis.rotated(gravityVec , -speed)

Turn Right

transform.basis = transform.basis.rotated(gravityVec , speed)

And you apply gravity with this

``````velocity -= transform.basis.z * gravityForce
``````

1 Like