thombruce / verse

🚀 A universe in progress
Other
8 stars 0 forks source link

Ship Orbitals #35

Closed thombruce closed 1 year ago

thombruce commented 1 year ago

The ship should orbit the body of the top-most sphere of influence it finds itself within.

At present, a planet has a simple circular orbit around a parent star (#27). This works because the planet is a child of the star entity and has an Orbit {} component.

If the ship were given the Orbit {} component and made the child of another entity, it would orbit that entity's origin, which means it could easily be made to orbit the planet while the planet orbits the star or to simply orbit the star.

As the ship moves however we need to be able to un-parent it from one entity and have it orbit another. We need to detect these changes at a certain distance from the parent entities, hence the terminology "sphere of influence".

The star's sphere of influence should extend to the bounds of the current star system. Planetary spheres of influence will be much smaller and will sit within the stellar sphere of influence.

Unsure how best to implement this yet...

As the player travels around, they should be able to place their ship in an orbit around each body in the system. As stated, the orbital system currently works for objects with an Orbit component and a parent in the entity hierarchy. So could we, by determining proximity to a massive object, change the parent of the ship entity? Or is there some alternative way we should come about this...

thombruce commented 1 year ago

What about other objects that enter the planetary system? Think comets/asteroids...

We eventually intend to implement Kepler orbits (#28) and some of these might have parabolic orbits which enter and exit the spheres of influence of other bodies.

Again, should this be a matter of parent-swapping or... is there some other way?


An alternative is to attach the orbital system to the parent body instead and apply it to all objects (with some component) within that parent's reach. Said "reach" is effectively its sphere of influence and could be determined by its mass (a variable I believe we need to know for Kepler orbits anyway). This would unfortunately interfere with descendant orbits around child objects....

Perhaps a free-floating object could "choose" its parent? It would look for objects with mass in its vicinity (the planetary system) and choose based on some equation of distance and mass (or sphere of influence - a radius). If the distance falls within the radius of an object's sphere, then that is its orbital parent. It may fall inside of many spheres, but it will choose the closest object.

_Note that for elliptical orbits, the sphere of influence of a child body is smaller at periapsis and bigger at apoapsis. See: https://en.wikipedia.org/wiki/Hill_sphere. For our purposes, I don't think this practically matters too much. Even though it would be interesting if the player set up an orbit in a sphere that shrunk not to include their orbiting object (ship or station), this event would be so rare and precise as to appear more like a bug than an intended feature... Maybe one day._

Does that seem like the way to do it then? Get distance to objects and iterate through them until you find the first object where that distance is less than the radius of the objects sphere of influence?

Sounds good to me.

And then with that information, either...

  1. Calculate the next step in the child's orbit around the parent directly.
  2. Set the object as its parent for handling by a separate orbital system.

See, I still don't know about messing about with the child-parent hierarchy... but there are other ways to do 2. You could set the object as a variable on the child's Orbit component. No messing about with the parent-child hierarchy - just set the value on the virtual child's component and use that instead.


That sounds very good to me. Now what about thrust mechanics? Ship flight controls?

...

Well, what about them? I think so long as one happens then the other, the adjustments to a body's position shouldn't matter and the equations will be correctly modified automatically. I don't even think it matters which order the systems run in... It might, but I don't think it does. This should have no negative consequence for the flight system... I think.

thombruce commented 1 year ago

The only way in which I imagine the flight controls interfere with the above is in that they will allow the player to adjust their orbit INSIDE OF the planet. And I have no idea what happens at close to 0 but the orbital speed is determined by radius.

Here's the formula for the x position (we do nearly the same for y):

(game_time.elapsed_secs() / orbit.semi_major_axis.sqrt()
    * ORBITAL_PERIOD_SCALING_FACTOR)
    .cos()
    * orbit.semi_major_axis;

So as the radius (semi_major_axis above) approaches zero... We divide by an exponentially smaller and smaller value until... Whoops! We divide by zero.

This is so absolutely fine for objects outside of the object, but as soon as we can't guarantee that... you're gonna have a problem.

This is why I've been thinking about Z-axis gravity (#23). If we can treat the orbit as a 3-dimensional one and pretend that any position within (or "over") the planet is actually extruded along the z-axis, we can prevent this issue.

It's just a question of when we treat an orbit as being around 3-dimensional space instead of 2-dimensional. For most distances outside of the object, it is reasonable and intuitive to have any positional adjustments reflected as a change in a flat orbit.

So... this is only applicable at small radii. Something like: IF orbitR < planetR THEN something ELSE regular_orbital_mechanics

Since the ship thrust should typically outpace orbital velocity, I think we can do something simple like... it's totally fine if their orbit flips directions. Just, within a certain sphere, their orbital position is determined by their present velocity and is calculated as an extrusion along the Z-axis.


Secondary concern: No idea how well any of these plays with the Rapier2D physics plugin. The plugin does expressly warn against setting the position of an entity directly (which orbital mechanics essentially do every tick) rather than having a force application modify its linear velocity instead.

My thinking was that after a positional change (caused by the orbital mechanics), the linear velocity should be unchanged and so the physics system would keep working as if normal. And in this case, it shouldn't matter which system updates first because the positional change would be factored in either way (they both ultimately change where the ship is from its current position).

I could be wrong about that, so it's something else to watch out for.

thombruce commented 1 year ago

What about Z-axis orbits that are at an angle, rather than straight across the center?

Well... for small radii we'll be extruding a circle into the Z-dimension. The actual angle of said circle doesn't matter a lot.

I think we need to implement the 3D orbits for small radii first and see what happens with our maths, then we can look to modify it after the fact. I'm trying to picture how a change in the ship's position or velocity should modify its extruded 3D orbit, but I'm having a failure of imagination in terms of how it ought to feel. Need to model something and play around with it.

thombruce commented 1 year ago

The need to decouple planets from the parent star (#37) might give us a mechanism for this,

The idea there is to attach the star as the parent entity not via .with_children but via a value on a component struct. If we obtain said struct mutably for the ship... we could change the parent to any body we want.

thombruce commented 1 year ago

So, I had a bit of a think about this on a walk earlier and realised I may be coming at this backwards.

How I've been doing it and was prototyping in my head for ship orbitals was to query the orbiting entity (the ship) and find nearby orbitals. But I think it makes more sense to come at this the other way around...

Query the orbitable bodies (stars, planets, moons) and then query the nearby orbiting bodies. This has the benefit of... _if there are no orbitables, then orbiting bodies will sit static in space (rather than floating around a non-massive point, which makes little sense).

So how would this work for ships...?

Well, a star or a planet would be captured by the orbitable query and a query for potential orbiting bodies would be executed. If any are found, we'd apply the orbital maths. Simple.

This could be refined by finding the closest distance between orbiter and orbitable where that distance does not exceed the radius of the orbitable's SOI (for most stars, this is the full extent of the scene; for planets it is a factor of the planet's mass (and if you wanna make it more complicated, also the star mass and the distance from the star)).

What about binary star systems? Yeah, they're a problem... these should technically orbit one another around a shared centre of mass and would have large overlapping SOIs. For certain distances, the orbit around them would draw a figure eight, as the relative distance to each changes.

From a programming POV, the simplest approach is to apply all orbital transforms. If I'm imagining the result of doing so correctly, this should look reasonably like the orbiting ship is orbiting the child... since said child will be moving relative to the parent too and error margins are pretty negligible. Some chance of orbital decay as a consequence, but this might provide simple artificial realism.

Okay but... the distance from Earth to Mars, for example, is less than the Earth-Sun distance. Right now, we don't account for mass in any way, so applying all orbits would favour the gravitation of Mars over the Sun. Yeah... hence SOIs.

At present, we have simple circular orbits... What happens if two bodies intersect in such a way that the orbital circles perfectly meet at the circumference? One body would adjust the orbit one way, the other might adjust it the other, resulting in a perfect equilibrium of position completely disregarding momentum.

Worse, actually, all orbits are presently counter-clockwise. So at intersections where one orbit takes over from the other for not fully contained SOIs, this could result in the orbiting body changing direction entirely.

Hmm... maybe momentum does need to be accounted for. And yet, I don't want to defer this to the physics system, as this would then not be predictable over time and would be prone to drift even in real time.


Okay then, not as solved as I thought. But... for SOIs within a single larger SOI, it should work reasonably.

Obviously this gets reworked with #28, but I think a lot of the same problems still exist. We still have to decide on the orbital directions of orbiting bodies, and they don't have a momentum (their position is just changing in space on the pixel level for each frame). This is difficult to remedy without the physics engine... and impossible to maintain with it.

What can we do?

Well, planets and stars are on rails and we can calculate those rails ahead of time. There's no problem here; even if the system grows in complexity, their orbital positions are still time-predictable.

For asteroids, comets and spacecraft... positional changes caused by momentum need to be accounted for, changing the radii of their orbits around parent bodies. They have what we might call DynamicOrbits. That said, when they are not under any external impulse, these dynamic orbits can fall back into predictable StaticOrbits - we just need to maintain a record of their semi-major axis, eccentricity, direction aaaaaaand... starting position and starting time (where and when it came to rest on this new orbit - which maybe Rapier2D can help us with; it is the precise moment and position the object was released from any impulse - the impulse creates the new orbital and the orbital is recorded for the planet starting from its new position and current time). Given which... it might be possible for the new orbit to also be complex.


That all sounds great... but I started this by talking about which entity to begin our query iteration from. And now I'm less sure. More thinking about this is required...

Do we run the orbit positioning system for each Orbitable querying for entities with an Orbit in turn?

Or do we run the system for each entity with an Orbit, querying for the Orbitables in turn?

Does it even matter?

Main concern is setting up masses and distances and limiting the ways in which the three-body problem arises. We have to solve for two-body systems independently... though we might consider some system which has the stable figure-8 solution to the problem somewhere in the galaxy: https://www.maths.ed.ac.uk/~ateckent/vacation_reports/Report_Faustino.pdf

thombruce commented 1 year ago

All of which is to say...

Orbital mechanics are gonna be a huge part of this project, but there are limits to what we can do and we should know those limits ahead of time so that we don't try to go beyond them.

If you're reading this, the aim of this simple 2D game is NOT to find a theory of quantum gravity.

thombruce commented 1 year ago

Added the v0.1.0 milestone.

Without the ship orbiting planets, the player ship can come to a full-stop in space and watch as the planet continues away in its orbit. This won't matter when orbital physics are rescaled (an orbital period should be closer to a year or whatever feels right than to a few minutes), as it will be less noticeable, but it's still very worthwhile to have in case the player decides to stay in orbit for an extended period. It's also just visually nicer to see your ship orbiting a planet, right?