Bundle of Project Extension Questions

Heya, wasn't sure the best place to put this. I wanted to make a thread where I'd be posting questions as I come up with them. I figured I would just use one thread instead of making new ones every time. I'm making an 'extension' and I am a little new to godot so if some of my questions seem basic or silly apologies in advanced. I'm also getting used to using ivoyager items as the main 'control' if that makes sense and the whole 'project builder' thing.


Question 1:
From my understanding Timekeeper is keeping track of everything with engine time that is updated every process tick that the game isn't paused. This is added to time (seconds from J2000 epoch) which is then used to return the number of solar days that have passed (using Julian days). Then it checks if it is the next day, and if it is it gets the Julian day number from that. Then finally it sets the Gregorian date using some math I don't quite understand yet, and calculates the hours, minutes, seconds.
I was wondering what might be the best way to change the calendar used if I wanted to use an alternative one, such as one that has 30 days for every month or another calendar variant. I assume I should just figure out the way to derive the date in this calendar from the Julian day count right? From what I can tell, this is only used for displaying the date and shouldn't mess up anything simulation wise.

Question 2:
The next question is about the simulation. There is a note that orbits are only 'valid' from between 3000BC and 3000AD. I believe this is because of the drift values (a, e, i rates?) that some of the objects have. My use case does not care about completely accurate orbital positioning with a given time, and through the course of it may extend past 3000AD, especially as I am thinking of a starting year of sometime between 2200 - 2400 and it may be possible that time exceeds this date. If I edit the data tables (copying them into my own folder and then overriding the tables in global through my project init) to remove all these rates, would this prevent any instability from occurring from future dates?

Question 3:
Spaceships are an important part of the project I am working on. They are pretty complex to implement for sure. What I am working on right now is their order system, namely navigation and actual movement. I plan on doing this how you mentioned where I let body/orbit 'carry' the ship along it's orbital path after I calculate what it will need to be (the hard part!). I was wondering what you think the best way of keeping track of timing / positioning for the orbit path hand offs would be? For example if the ship is doing a relatively simple Hohmann transfer maneuver to increase it's altitude it would look like the following:
Create the target orbit
|-> calculate the elliptical transfer orbit and time to execute the orbit (immediate, delayed, etc depending on various conditions)
|-> wait until it's time to change to the transfer orbit
|-> set orbit to the transfer orbit
|-> wait until it's time to change to the target orbit
|-> set orbit to the target orbit
|-> done

All maneuvers are going to be executed instantly for simplicity's sake at least for now. Maybe in the future that'll change.

What's the best way to figure out 'when' to do the actual change? I noticed the scheduler script seems to support custom signals but I don't really understand how to use it (or even if it's appropriate). It seems more performant as well than my initial idea of every ship checking if it's time every process interval.


Also if you prefer in the future I make new posts for future questions I can do that, just let me know. I know I'll have more questions!

Many thanks :)

Comments

  • edited May 29
    Question 1:
    From my understanding Timekeeper is keeping track of everything with engine time that is updated every process tick that the game isn't paused. This is added to time (seconds from J2000 epoch) which is then used to return the number of solar days that have passed (using Julian days). Then it checks if it is the next day, and if it is it gets the Julian day number from that. Then finally it sets the Gregorian date using some math I don't quite understand yet, and calculates the hours, minutes, seconds.
    I was wondering what might be the best way to change the calendar used if I wanted to use an alternative one, such as one that has 30 days for every month or another calendar variant. I assume I should just figure out the way to derive the date in this calendar from the Julian day count right? From what I can tell, this is only used for displaying the date and shouldn't mess up anything simulation wise.
    Yeah, the sim only needs "time", which is seconds from J2000. JDN and solar day are used to generate "date" and "clock" ints, which are irrelevant to sim function other than GUI display. Mostly you should get sim time from Global.times[0]. Keep a local reference to the "times" array in your class. Or, for some special needs, hook up to Timekeeper "processed" signal.

    Gregorian date equation is wild. I just copied from Wikipedia. The whole topic of Julian Day and JDN and UT is a deep rabbit hole.

    So yes, you can do anything you want with the calendar and clock, even dispose of JDN and solar day concepts entirely, without affecting the sim. To do this correctly, you should subclass Timekeeper (substituting your subclass in ProjectBuilder) and override its functions to generate the clock and calendar values that you want.

    Question 2:
    The next question is about the simulation. There is a note that orbits are only 'valid' from between 3000BC and 3000AD. I believe this is because of the drift values (a, e, i rates?) that some of the objects have. My use case does not care about completely accurate orbital positioning with a given time, and through the course of it may extend past 3000AD, especially as I am thinking of a starting year of sometime between 2200 - 2400 and it may be possible that time exceeds this date. If I edit the data tables (copying them into my own folder and then overriding the tables in global through my project init) to remove all these rates, would this prevent any instability from occurring from future dates?
    Nothing will break outside of 3000BC-3000AD. It's just no longer a "valid" estimate of body positions using NASA/JPL provided values. The sim caps adjustments to certain orbit elements outside this range: specifically, a, e and i, since these could really change the character of the orbit. It will continue to adjust Om and w since these are cyclical (precessions). You can see this capping in tree_refs/orbit.gd.

    Note: You could set Global.dynamic_orbits = false for simplified orbits. With this setting orbit element "rates" are ignored. Positions will be correct near J2000 but less so far from J2000. However, you will lose certain orbital dynamics including precessions. So, for example, you could not have a satellite with a sun-synchronous orbit since that requires an Om rate.

    Note 2: There WILL be problems at some distant time values related to float precision. Godot 3.x is officially single-precision while Godot 4.0 will allow double-precision. HOWEVER, the issue is complicated because GDScript float already "holds" a double precision value and some (but not all) GDScript operations maintain double precision (I've tested this). Timekeeper is adding a value of 0.017 to time at "real time" game speed assuming 60 fps. If you assume single precision (=2^-24), then time approaching 285,212 s (= ~3 days) would already be problematic. That's clearly not the case. Assuming double precision (=2^-53), then time values approaching 153,122,387,330,596 s are problematic. So, we should be good to about J2000 +- 4.8 million yrs.

    [Edited to fix math errors above.]

    Question #3 is a tough one, I'll get to that in a bit...
  • edited May 30
    Question 3:
    Spaceships are an important part of the project I am working on. They are pretty complex to implement for sure. What I am working on right now is their order system, namely navigation and actual movement. I plan on doing this how you mentioned where I let body/orbit 'carry' the ship along it's orbital path after I calculate what it will need to be (the hard part!). I was wondering what you think the best way of keeping track of timing / positioning for the orbit path hand offs would be? For example if the ship is doing a relatively simple Hohmann transfer maneuver to increase it's altitude it would look like the following:
    Create the target orbit
    |-> calculate the elliptical transfer orbit and time to execute the orbit (immediate, delayed, etc depending on various conditions)
    |-> wait until it's time to change to the transfer orbit
    |-> set orbit to the transfer orbit
    |-> wait until it's time to change to the target orbit
    |-> set orbit to the target orbit
    |-> done

    Exactly the right way to do this! For other readers, this is a Patched Conic Approximation. I'd like to formalize this in the core ivoyager submodule, perhaps with a new object "NavPath" or something like that. It's just a set of intersecting orbit segments, with each intersection having a specific time and place and delta-v. I want this in our Planetarium for Voyager 1 & 2, New Horizons, etc. And also for a game I'm developing...

    What's the best way to figure out 'when' to do the actual change? I noticed the scheduler script seems to support custom signals but I don't really understand how to use it (or even if it's appropriate). It seems more performant as well than my initial idea of every ship checking if it's time every process interval.

    Yes, this is one of the reasons I created Scheduler. It can be done with interval_connect() like this:
    var scheduler: Scheduler = Global.program.Scheduler
    var times: Array = Global.times
    
    func create_callback(callback_time: float, target: Object, method: String, args := []) -> void:
    	var current_time: float = times[0]
    	var interval := callback_time - current_time
    	scheduler.interval_connect(interval, target, method, args, CONNECT_ONESHOT)
    The API is similar to Godot's connect/disconnect, except you are specifying game time interval rather than some object's signal. Code above would call method in the target object with args at callback_time. You don't need interval_disconnect() due to flags = CONNECT_ONESHOT. I'll add a Scheduler public function that allows you to specify callback_time directly rather than having to calculate interval as above (this would be implicitly oneshot).

    Spaceships are an important part of the project I am working on.

    And mine and everyone else's too! There is quite a bit of work to do. Some of it will be game-specific. But some should be core I, Voyager. There are bits of code here and there: for example, an unimplemented function `Orbit.perturb(delta_v: Vector3, at_time: float)`. There is a quite complex (and possibly confusing) system for lazy init of models that is currently used for small moons. But it's really there to support many 1000s or 10000s of asteroids plus spaceships.


    Questions here are fine. They are searchable in the forum and I can link back when they come up again.


Sign In or Register to comment.