How do I get my spaceship in orbit...

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By keke
:warning: Old Version Published before Godot 3 was released.

Hello, I’m brand new to godot, and Im working on a 2D space game. I’ve gone through the docs and set up a spaceship which I can fly and a planet. I have two questions, one easy and one complicated

Easy question: How do I apply_impulse relative to the ships rotation? i.e. when I thrust I want the ship to go the direction it’s pointing. Right now it uses some dumb trig I did, so it works fine, but Im sure “local axes” are built into godot somehow.

Hard question:

Here’s my gravity code (runs in _integrate_forces under the ship):

var distance=get_pos().distance_to(planet.get_pos())
var gravity=(self.get_pos()-planet.get_pos()).normalized()
gravity*=(-(G*planet_mass*get_mass())/pow(distance,2))
apply_impulse(Vector2(0,0),gravity)

(Basically, I get the distance to the planet, get a normalized vector thats points towards the planet, multiply/account for the inverse square rule, and apply an impulse with that vector)

My problem is this: I want to write a function that puts the ship in a perfect circular orbit (not with the thrusters - just magically, for when the scene starts). Google tells me that orbital speed is equation. Here’s the function so far:

func make_orbit():
var distance=self.get_pos().distance_to(planet.get_pos())
var magnitude=sqrt( (G*(get_mass()+planet_mass))/distance )

var velo=Vector2(0,-magnitude)
set_linear_velocity(velo)

(You’ll notice that this doesn’t take into account where the ship is around the planet - i.e. the angle - so right now this only works when the angle from the ship the the planet is 0 - so on the left or on the right, in line with the planet. I’m testing with the ship directly to the left of the planet, so this can’t be the problem)

For some reason, this velocity is way too slow, and the ship hits the planet. Any idea why?

:bust_in_silhouette: Reply From: Warlaan

General advice: don’t use physics unless you explicitly want physically correct behavior. A game is a game, not a simulation.
In your case you don’t want a simulation to determine whether or not your space ship will crash into the planet, you just want to space ship to orbit around the planet, so here’s what I would do:

Place a Node2D at the center of the planet. Attach a Sprite (or an instance of your Spaceship scene) to it with an offset so that it is at the correct orbit distance. Rotate the Node2D. Done.

When you want to leave the orbit all you need to do is calculate the current direction and speed of the space ship, detach it from the Node2D and set the correct physics values so that the physics engine can seamlessly continue from where your orbit animation left off.

If you want you can add a Tween that acts like an autopilot that moves the space ship in and out of orbit so the player doesn’t crash into the planet during these maneuvers.

Thats a really interesting idea, but I’m not sure if it would work? if the Node2D was rotating too fast or too slow, the ship would fly away/crash after it detatched. I can calculate the speed it would need to rotate, but then I might as well just set the ship to that speed and have a real orbit.

To clarify, I will only be calling this function in _ready() - I’m only using magic so my craft starts in a circular orbit. After that, everything is physically correct.

keke | 2016-12-19 09:43

:bust_in_silhouette: Reply From: Jatz
  1. you don’t need gravity code, godot comes with spherical gravity included. just put a Area2D with the planet and set the Area2D variable gravity point or call the function is_grvity_point(true) or the Area2D

  2. velocity is too slow because you did not take time into account.

the problem is in the gravity code, gravity should not be applied with an impulse, it should be applied using force… apply_force(gravity) should work, or apply_impulse(gravity*state.get_step()), state being the parameter that is used in _integrate_forces()

Godot’s physics is pretty stable, the collision detection still needs a little work, but it’s good enough for an approximation of an orbit (just don’t expect it to remain accurate for a long time, since it’s meant to be used for games that don’t have such a high need for accuracy as simulations do)

gravity*state.get_step() did it. I’ll investigate that Area2D gravity - it sounds like it could save me a lot of time. I can’t apply gravity as a force because the vector is constantly changing, both in magnitude and direction, hence the need to update constantly. Thanks!

keke | 2016-12-19 19:56

So what sort of node does the ship need to be to be subject to the planet’s gravity? Another node2d with the same variable enabled?

Judd Gledhill | 2018-06-11 19:57