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???
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
var adjust: Vector3 = adjustq.get_angle()
player.rotate(adjust)
Of course, you can simplify it, I just split it into easier to read steps.
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.