Going Forward Around a planet

Godot Version

4.2.1 in C#

Details

So I tried to do it with this code :

state.ApplyCentralForce(-player.GlobalTransform.Basis.Z*50);

(I’m getting the foward vector from the player CharacterBody3D, which is a child node of the rigidBody (I did that because I locked the rotation of the RB)).
Like this :
screen

I checked, of course, if the rotation of the player was correct. (and it is)

Main Problem

It’s not going in the right direction, and it sometimes get “locked”, like its not even moving anymore.

There is not enough information here to attempt to help you with your problem.

Please provide information that answers all questions in the following list:

  1. What is currently happening? Describe this in detail.
  2. What do you want to happen; what is “the right direction”?
  3. How does your system work? Show more than one line of code.
    3.1 How are you currently aligning the rigid body’s rotation to that of the planet?
  4. Describe your reasoning for locking the rotation of your rigid body. Which axes did you lock and why?
2 Likes

Have you considered rotating the planet under the player? Besides that the way I’d do it is have a node constantly teleporting to the player (not childed), get the angle from the planet to that node, then rotate the player to that angle (maybe lerp the camera for smoothness). But yeah the information provided is too vague to help fix whatever you’re trying to do

Here’s your answer, apologize for the very imprecise help request :

  1. I set the rotation of the player to be aligned on a downward vector, pointing to the planet/sphere, but (see 2).

  2. The right Direction is the forward vector of the player

  3. LookAt(planet.Position); RotateObjectLocal(Vector3.Right, Mathf.DegToRad(90.0f)); RotateObjectLocal(Vector3.Up, Mathf.DegToRad(90.0f));
    I’m rotating it at the end since the rotation of LookAt is making it forward, not Upward/downward.

  4. I locked every axis of my rigibody to prevent it from spinning and doing some unexpected behavior (such as adding speed, since it spin…).

I did not understand your method, like you want to set it the rotation of the player to the planet rotation ? And rotating the planet under the player isn’t a very good option in my case, since a plan to make it multiplayer (Of course there would be some methods with that system but it would just be too hard, I think).

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

I mean set the player’s rotation relative to the planet to the direction of the teleporting-player-following node relative to the planet, like:

var player:CharacterBody3D
var player_pos_node:Node3D
var planet
func _physics_process(delta)->void:
	if player_pos_node.position == player.position and player.rotation == (planet.rotation - player_pos_node.rotation):
		return
	if player_pos_node.position != player.position:
		player_pos_node.position = player.position
	if player.rotation != (planet.rotation - player_pos_node.rotation):
		player.rotation = (planet.rotation - player_pos_node.rotation)
# subtract 90 from an axis or two to get the player facing forward

You method is weird. I guess it could work, but locking axes won’t help. Even if it did somehow work it would just gloss over errors in the rotation algorithm.

it sometimes get “locked”, like its not even moving anymore.

That’s probably a situation in which the only directions in which the player is capable of moving are along axes you’ve locked.

Also yeah set gravity to go towards the center of the planet if you haven’t already

Thanks for the script, I will convert it in C# and see if it work ! But with that I do clearly understand that I was rotating my player forwardly and not upwardly (weirdly because I would be able to see the difference between upward and forward, like i don’t know just see the code)

		LookAt(planet.Position);
		RotateObjectLocal(Vector3.Right, Mathf.DegToRad(90.0f));
		RotateObjectLocal(Vector3.Up, Mathf.DegToRad(90.0f));

And only with 3 lines it rotate the player, not that this script is attached to the playerController

LookAt has a second parameter, which defines the up vector. With your code you lose information because LookAt() doesn’t know what the last rotation was like