Solar System Sim

Alright, back with another one. I’ve been slowly making my way through understanding this…it’s been painful to say the least.

So here’s where I’m at:

  1. I start with creating an array of GameObjects…three to be exact
  2. I attach a VERY basic (it literally only has mass) nBody script to each of the GameObjects
  3. I attach a Rigidbody to and turn off gravity for each of the GameObjects
  4. I set the mass of the Rigidbody equal to the mass of the simple nBody script
  5. Since it’s a public class (for testing) and I’m simply manually placing the objects in the array from above, I set index 0 equal to the sun and then make it kinematic (since I’m wanting a fixed reference point for things to rotate around)
  6. I add an initial force (I ACTUALLY NEED HELP COMING UP WITH A WAY TO CALCULATE THIS) which I largely just…make up until things look ‘right’.
  7. Next in FixedUpdate() I start first with the first planet, determine distances between the objects and apply forces…then I start on the second planet object…

Here’s the code so far, and here’s the help I’m asking for:

As you can see in bold above, I haven’t hit on a method for calculating the initial force to establish a more or less uniform orbit, does anyone have any insights? I’ve got the following data (which actually isn’t implemented in this code):

for my planetary system. I know how to find the velocity, but the problem is…when I go to astronomical scales things tend to stop working…

Also, is my implementation (which is 100% brute force) also more or less correct? I need to incorporate time, which means I probably need to dig into integration…which I haven’t done a whole lot of, but I should be able to work my way through it.

Oh, one other thing that I’ve noticed, and I suspect it’s because of how the current code is implemented, when the bodies collide, they tend to go flying away from each other at tremendous speeds. I don’t think that’s quite right behaviorally…so with my implementation, what part of my rudimentary understanding of how this works is broken or causing that ‘freak out’ to occur? Or is that just something inherent in the rigidbody?

Anyway, code! This current implementation ignores the use of the constants currently also…and this almost gets a figure 8 around the second planet.

Masses for the bodies in my scene are:
Sun = 10
Planet 1 = 0.387
Planet 2 = 10

using UnityEngine;
using System.Collections;

public class NBODYCONSTANTS
{
    public const float EARTHRADIUS      = 6371000.0f;   //m
    public const float EARTHDENSITY     = 5510.0f;      //kg/m^3
    public const float EARTHMASS        = 5.972E24f;    //kg
    public const float EARTHGRAVITY     = 9.806f;       //m/s^2
    public const float EARTHFORCE       = 5.294E33f;    //N
    public const float SUNMASS          = 1.989E30f;    //kg
    public const float GRAVCONSTANT     = 6.667E-11f;   //N m^2 / kg^2
    public const float AU               = 1.496E11f;    //m
    public const float SEC2YR           = 3.171E-08f;
}


public class NBodyTest : MonoBehaviour
{
    public GameObject[] nBody = new GameObject[3];

    void Awake()
    {
        for (int i = 0; i < nBody.Length; i++)
        {
            nBody[i].AddComponent<Rigidbody>();
            nBody[i].GetComponent<Rigidbody>().useGravity = false;
            nBody[i].GetComponent<Rigidbody>().mass = nBody[i].GetComponent<nBodySimple>().nBodyMass;
        }
        nBody[0].GetComponent<Rigidbody>().isKinematic = true;

        nBody[1].GetComponent<Rigidbody>().AddForce(Vector3.left * 32.25f);
        nBody[2].GetComponent<Rigidbody>().AddForce(Vector3.left * 500.0f);
    }

    void Start()
    {


    }

    void FixedUpdate()
    {
        //Sun and Planet 1
        Vector3 line = nBody[0].transform.position - nBody[1].transform.position;
        //Sun and Planet 2
        Vector3 line2 = nBody[2].transform.position - nBody[1].transform.position;

        float dist1 = Vector3.Distance(nBody[0].transform.position, nBody[1].transform.position);
        float dist2 = Vector3.Distance(nBody[2].transform.position, nBody[1].transform.position);

        line.Normalize();
        line2.Normalize();

        nBody[1].GetComponent<Rigidbody>().AddForce(line * (nBody[0].GetComponent<Rigidbody>().mass * nBody[1].GetComponent<Rigidbody>().mass) / (dist1 * dist1));
        nBody[1].GetComponent<Rigidbody>().AddForce(line2 * (nBody[1].GetComponent<Rigidbody>().mass * nBody[2].GetComponent<Rigidbody>().mass) / (dist2 * dist2));

        //Sun and Planet 2
        Vector3 line3 = nBody[0].transform.position - nBody[2].transform.position;
        //Planet 2 and Planet 1
        Vector3 line4 = nBody[2].transform.position - nBody[1].transform.position;

        float dist3 = Vector3.Distance(nBody[0].transform.position, nBody[2].transform.position);
        float dist4 = Vector3.Distance(nBody[2].transform.position, nBody[1].transform.position);

        line3.Normalize();
        line4.Normalize();

        nBody[2].GetComponent<Rigidbody>().AddForce(line3 * (nBody[0].GetComponent<Rigidbody>().mass * nBody[2].GetComponent<Rigidbody>().mass) / (dist3 * dist3));
        nBody[2].GetComponent<Rigidbody>().AddForce(line4 * (nBody[2].GetComponent<Rigidbody>().mass * nBody[1].GetComponent<Rigidbody>().mass) / (dist4 * dist4));
    }
}

You seen this yet? It deals with a lot of the problems you are likely to face. In fact go buy and play the game. You’ll learn more about orbital mechanics in a few hours of play the you will in a three year physics degree.

https://www.youtube.com/watch?v=mXTxQko-JH0

This would be the space kraken. Also known as floating point precision errors. There are several ways to deal with these.

  • Stay on a small scale
  • Use your own physics system, possibly deterministic and with higher precision

If you really want n-body orbital physics you can’t have any things set to kinematic. n-body systems rotate around the shared centre of mass, which is often empty.

This system is likely to be inherently unstable. Most ‘real’ systems only have one significant gravitational neighbour. The earths orbit is pretty much only reliant on the sun. The moon on the earth and so forth. Binary systems do exist. And astronomers have even discovered star systems with as many as six stars. But even then they are structured as binary pairs that orbit their common centre of gravity.

Iterative physics systems also tend to decay over time. For a quick demonstration make a demo scene with a ball bouncing on a plane with perfect elasticity. In theory the ball should bounce in place forever. But the system is inherently unstable in unity.

Not trying to dissuade you. Just pointing out you have your work cut out to get a decent n-body simulation running in Unity.

1 Like

Awesome! I remember watching that video back about a year ago now, it’s a great refresher on things to avoid!

So, you’re right. With each body interacting with each body the way I had it…things were very unstable. When I set things up to ONLY work with a planet/sun relationship things smooth out and work as expected. So I guess that means if I really want an n-body sim…I don’t really need every body interacting and influencing every body…and keep my sanity :smile:

The solution of using a deterministic system where time drives the train makes a lot of sense…as does the Spheres Of Influence. Amazingly enough, I’ve actually got a working Floating Origin implementation so I’ve at least got that down.

What I’ve been slowly realizing is that if I want to make the game I’m out to make, I’m going to have to make a lot of compromises, and so long as it’s ‘close enough’ life is good. I’ve got about…201 hrs in KSP so I definitely love it.

You’ve definitely not dissuaded me at all! I appreciate your insight. You’ve pointed me in a new and I think ultimately less sanity taxing route!

1 Like

This is a VERY rough start to trying to implement this…so bear with me and don’t judge to harshly :wink:

I start with first calculating the bulk of my parameters in the spreadsheet…I then take the basic data (semi-major axis, eccentricity, rotation speed in degrees per day) and then do a quick update on the position of a child object in the scene. The hierarchy goes:

Manager

  • Rotation Point
    –Planet

The rotation point is probably going to go away actually. I may keep one just to seed the rotation and make life a little easier, but otherwise…it’s not really necessary.

Since I know the relevant info (which will soon be calculated solely within unity) I just put that data in and update the planet object’s position based on the radius formula for an ellipse. This radius value is updated by the rotation of the world (which the rotation speed I set to be degrees per hour so that when paired with Time.DeltaTime 1 hour = 1 day in the game…I can also time step (hooray!). So all the data is essentially generated via known information and then the positions of the planets are moved through their orbital paths.

Things I still need to figure out:

How to incorporate epoch data. For now though, I can at a minimum get the orbits plotted…and then start working on spheres of influence for gravity…here’s the code!

Is this more or less on the right track you think?

using UnityEngine;
using System.Collections;

public class RailsTest : MonoBehaviour
{
    public float rotation = 0.985f; //degrees per day
    public float semiMajorAxis = 0.387f;
    public float eccentricity = -0.25f;
    public int timeStep = 100;

    float time;

    GameObject child;

    Vector3 childPosition;

    float radius;

    // Use this for initialization
    void Awake ()
    {
        child = GameObject.Find("Planet1");
       
        childPosition = child.transform.position;

        radius = semiMajorAxis * (1 - Mathf.Pow(eccentricity, 2.0f)) / (1 + eccentricity * Mathf.Cos(transform.eulerAngles.y * Mathf.Deg2Rad));

        childPosition.x = radius * Mathf.Sin(transform.eulerAngles.y * Mathf.Deg2Rad);
        childPosition.z = radius * Mathf.Cos(transform.eulerAngles.y * Mathf.Deg2Rad);
    }
   
    // Update is called once per frame
    void Update ()
    {
        transform.Rotate(Vector3.up, rotation * (Time.deltaTime * timeStep));

        radius = semiMajorAxis * (1 - Mathf.Pow(eccentricity, 2.0f)) / (1 + eccentricity * Mathf.Cos(transform.eulerAngles.y * Mathf.Deg2Rad));

        childPosition.x = radius * Mathf.Sin(transform.eulerAngles.y * Mathf.Deg2Rad);
        childPosition.z = radius * Mathf.Cos(transform.eulerAngles.y * Mathf.Deg2Rad);

        child.transform.position = childPosition - transform.position;

        time += Time.deltaTime;

        //Debug.Log(time);
        Debug.Log(radius);
    }
}

After a bit of work I’ve now got this to present and I have one small problem:

While I’ve got a working Kepler Solver implemented…and it outputs accurate data, I think the while loop (read: I know…) is causing me some problems. Anyone have any ideas on how to better integrate the Kepler Solver and make it more realtime? That while loop slows things down, especially when a time warp is set.

Here’s the updated code. I think once the Kepler Solver is tweaked this will work out really nice for moving a planet through it’s orbit. This probably is way more than is really needed, but it’s getting me a fair mount of accuracy so I’m happy with that. I guess if worse comes to worse I just strip out the Kepler bit and move the planets based on the data I can easily compute…won’t be accurate, but it’ll work.

Major features of this code attempt:

EpochTimer: calculates the date based on the reference of 1 January 2000, 0:00:00 UTC. Feed this Time.DeltaTime and it keeps tabs on things. This allows you to pick a time to start the sim and everything will adjust accordingly.

Sun: This is a bare bones implementation right now. Eventually it’ll hold information for habitable zones and other stuff like that which will in turn be used to generate atmosphere and other data for the planets.

Planet: All the requisite data for calculating the planet data and inputs to generate that data are there. Still gotta get the sphere of influence and ‘fake gravity’ implemented…which will probably be a separate script.

Anyway, code!

using UnityEngine;
using System.Collections;

public class NEWPLANETCONSTANTS
{
    public static float PLANETRADIUS   = 127420f;       //m, 2% of the actual Earth
    public static float PLANETDENSITY  = 275500f;       //kg/m3, 48.26255 times more dense than Earth
    public static float VOLUME         = (4.0f / 3.0f) * Mathf.PI * Mathf.Pow(PLANETRADIUS, 3.0f);
    public static float PLANETMASS     = PLANETDENSITY * VOLUME;     //kg, 0.04% of the Earth
    public static float AU             = 1.496E9f;      //m, 1% of an actual AU
    public static float GRAVITY        = 9.806f;        //m/s, Earth norm
    public static float SUNMASS        = 7.956E26f;     //kg, 0.04% of the Sun
    public static float GRAVCONSTANT   = 6.667E-11f;    //Universal Gravity Constant
    public static float SEC2DAYS       = 1.1574E-5f;    //Seconds to Days         
}

public class newSun
{
    public float stellarMass                = 1.0f;     //Sol
    public float stellarLuminosity          = 1.0f;     //Sol
}

public class EpochTimer
{
    //Initialized to January 1st, 2000, 0:00 UTC
    private int year    = 2000;
    private int month   = 1; //1 - 12
    private int day     = 1; //1 - 31
    private int hour    = 0; //0 - 24
    private int min     = 0; //0 - 60
    private int sec     = 0; //0 - 60

    private float systemTime;
    private float temp  = 0.0f;

    public void SetSystemDate( int yr, int mo, int d, int h, int m, int s)
    {
        year    = yr;
        month   = mo;
        day     = d;
        hour    = h;
        min     = m;
        sec     = s;
    }
  
    public void UpdateSystemDate(float s, float y)
    {
        temp += s;

        if (temp >= 60)
        {
            min++;
            temp = 0;
        }

        if (min >= 60)
        {
            hour++;
            min = 0;
        }

        if (hour >= 24)
        {
            day++;
            hour = 0;
        }

        if (day >= y)
        {
            year++;
        }
        //Debug.Log("Year " + year + " Day " + day + " Hour " + hour + " Min " + min + " Sec " + temp);
    }

    public float GetDate()
    {
        int d = 367 * year - (7 * (year + ((month + 9) / 12))) / 4 + (275 * month) / 9 + day - 730530;
        float t = (hour / 24.0f);// + (min / 60.0f) + (sec / 60.0f);

        systemTime = (float)d + t;

        return systemTime;
    }
}

public class newPlanet : MonoBehaviour
{
    public float timeStep = 1.0f;
    //This should just about cover all of the major planetary elements the user can define...
    public float semiMajorAxis              = 1.0f;         //AU
    public float planetRadius               = 1.0f;         //Earth
    public float planetDensity              = 1.0f;         //Earth
    public float orbitalEccentricity        = 0.017f;  
    public float orbitalInclination         = 0.0f;         //deg
    public float argumentOfPeriapsis        = 0.0f;         //deg
    public float longitudeOfAscendingNode   = 0.0f;         //deg
    public float M0                         = 357.529f;     //deg, initial position at T = 0
    //The rest of these values are generated by the program...
    private float mass;                 //kg
    private float surfaceGravity;       //m/s
    private float orbitalPeriod;        //hrs
    private float perihelionDistance;   //AU
    private float aphelionDistance;     //AU
    private float n;                    //deg/day
    private float n_s;                  //deg/sec
    private float T;                    //Epoch date
    private float M;                    //Mean anomaly
    private float E;                    //Eccentric anomaly
    private float v;                    //True anomaly
    private float r;                    //AU, distance to the sun

    private float x;
    private float y;
    private float z;

    private Vector3 position;           //AU, from the sun

    private newSun sun;
    private EpochTimer timer;

    GameObject planet;

    void Awake()
    {
        sun = new newSun();
        timer = new EpochTimer();
        timer.SetSystemDate(2004, 1, 0, 0, 0, 0);

        CalculateMass();
        Debug.Log("Mass " + mass + " in Planets");
        CalculateSurfaceGravity();
        Debug.Log("Surface Gravity " + surfaceGravity + " in Planet Normal");
        CalculateOrbitalPeriod();
        Debug.Log("Orbital Period " + orbitalPeriod + " in Days");
        CalculateOrbitalDailyMotion();
        Debug.Log("Orbital Rotation Rate " + n + " deg/day");
        Debug.Log("Orbital Rotation Rate " + n_s + " deg/sec");

        planet = GameObject.Find("Planet1");
    }
   
    void Update()
    {
        timer.UpdateSystemDate(Time.deltaTime * timeStep, orbitalPeriod);
        T = timer.GetDate();
        CalculateMeanAnomaly();
        KepplerSolver(M, 5);
        CalculateTrueAnomaly(E, 5);
        CalculateDistanceFromSun();
        //Debug.Log("T " + T + " M " + M + " E " + E + " v " + v + " r " + r);
        CalculatePlanetPosition();

        planet.transform.position = new Vector3(y, z, x);
    }

    //This calculates and stores the mass of the planet in 'Planets', where 1 Planet = 2.387E21 kg
    void CalculateMass()
    {
        //First we need to figure out the volume of the planet
        float v = (4.0f / 3.0f) * Mathf.PI * Mathf.Pow(planetRadius * NEWPLANETCONSTANTS.PLANETRADIUS, 3.0f);
        //Next calculate the density
        float d = planetDensity * NEWPLANETCONSTANTS.PLANETDENSITY;
        //Set mass = volume * density / PLANETMASS so the stored value is in 'Planet' masses
        mass = (v * d) / NEWPLANETCONSTANTS.PLANETMASS;
    }
    //This calculates and stores the surface gravity of the world in 'Planetary Gravities', where 1 'Planetary Gravity' = 9.806 m/s/s
    void CalculateSurfaceGravity()
    {
        //First calculate the radius of the planet
        float r = planetRadius * NEWPLANETCONSTANTS.PLANETRADIUS;
        //Next calculate the mass
        float m = mass * NEWPLANETCONSTANTS.PLANETMASS;
        //Set surfaceGravity = GRAVCONSTANT * d / r^2 / GRAVITY
        surfaceGravity = (NEWPLANETCONSTANTS.GRAVCONSTANT * m / Mathf.Pow(r, 2.0f)) / NEWPLANETCONSTANTS.GRAVITY;
    }
    //This calculates the orbital period in days
    void CalculateOrbitalPeriod()
    {
        //First calculate the orbital distance
        float r = Mathf.Pow(semiMajorAxis * NEWPLANETCONSTANTS.AU, 3.0f);
        //Next calculate the gravity bits
        float g = NEWPLANETCONSTANTS.GRAVCONSTANT * ((sun.stellarMass * NEWPLANETCONSTANTS.SUNMASS) + (mass * NEWPLANETCONSTANTS.PLANETMASS));
        //
        orbitalPeriod = 2.0f * Mathf.PI * Mathf.Sqrt(r / g) * NEWPLANETCONSTANTS.SEC2DAYS;
    }
    //Calculate the daily motion of the planet
    void CalculateOrbitalDailyMotion()
    {
        //Calculate the rate of rotation in degrees/day
        n = 360.0f / orbitalPeriod;

        //1 day = 24 minutes of real time
        float min = orbitalPeriod * 24.0f;
        float sec = min * 60.0f;
        //Convert to deg/sec
        n_s = 360.0f / sec;
    }
    //Calculate mean anomaly
    void CalculateMeanAnomaly()
    {
        //Mean Anomaly = M0 + n * T
        float temp = M0 + n * T;
        M = temp - (Mathf.Floor(temp / 360) * 360);
    }
    //Solve Kepplers Equation
    void KepplerSolver(float m, float dec)
    {
        float K = Mathf.PI / 180.0f;

        int iMax = 30, i = 0;

        float delta = Mathf.Pow(10, -dec);

        float temp, F;

        m = m / 360.0f;

        m = 2.0f * Mathf.PI * (m - Mathf.Floor(m));

        if (orbitalEccentricity < 0.8f)
            temp = m;
        else
            temp = Mathf.PI;

        F = temp - orbitalEccentricity * Mathf.Sin(m) - m;

        while ((Mathf.Abs(F) > delta) && (i < iMax))
        {
            temp = temp - F / (1.0f - orbitalEccentricity * Mathf.Cos(temp));

            F = temp - orbitalEccentricity * Mathf.Sign(temp) - m;

            i++;
        }

        temp = temp / K;

        E = Mathf.Round(temp * Mathf.Pow(10, dec)) / Mathf.Pow(10, dec);
    }
    //Calculate the true anomaly
    void CalculateTrueAnomaly(float e, float dec)
    {
        float K = Mathf.PI / 180.0f;

        float S = Mathf.Sin(e * Mathf.Deg2Rad);

        float C = Mathf.Cos(e * Mathf.Deg2Rad);

        float FAK = Mathf.Sqrt(1.0f - Mathf.Pow(orbitalEccentricity, 2.0f));

        float phi = Mathf.Atan2(FAK * S, C - orbitalEccentricity) / K;

        v = Mathf.Round(phi * Mathf.Pow(10, dec)) / Mathf.Pow(10, dec);
    }
    //Calculate the position of the planet
    void CalculateDistanceFromSun()
    {
        r = (semiMajorAxis * (1 - Mathf.Pow(orbitalEccentricity, 2.0f))) / (1 + orbitalEccentricity * Mathf.Cos(v * Mathf.Deg2Rad));
    }
    //Calculate the position of the Planet
    void CalculatePlanetPosition()
    {
        float x1 = Mathf.Cos(longitudeOfAscendingNode * Mathf.Deg2Rad);
        float x2 = Mathf.Cos((argumentOfPeriapsis * Mathf.Deg2Rad) + (v * Mathf.Deg2Rad));
        float x3 = Mathf.Sin(longitudeOfAscendingNode * Mathf.Deg2Rad);
        float x4 = Mathf.Cos(orbitalInclination * Mathf.Deg2Rad);
        float x5 = Mathf.Sin((argumentOfPeriapsis * Mathf.Deg2Rad) + (v * Mathf.Deg2Rad));

        x = r * (x1 * x2 - x3 * x4 * x5);
        y = r * (x3 * x2 + x1 * x4 * x5);
        z = r * x4 * x5;
    }

}

So, another update on the ‘Rails System’. It’s working, except for one minor hiccup when the planet transitions from one year to the next. It jumps, and then it’ll stable out for a few years and then jump and then stable out…Not sure why, well…I suspect the issue lies in that in this incarnation of the system I’m not yet calculating all of the elements using user input…The time warp works, which is awesome! and so do the inclination, longitude of perihelion and argument of pariapsis…even the Kepler solver is working…which makes me happy. I think once everything gets properly calculated mass, etc. wise the ‘jump’ will even out. Anyway, the code! If anyone has insights into why it’s jumping other than my own, please let me know!

using UnityEngine;
using System.Collections;

public class Rails : MonoBehaviour
{
    public float M0 = 357.5291f;
    public float timeStep = 1;

    public float orbitalPeriod = 18.271f;
    public float semiMajorAxis = 1.0f;
    public float eccentricity = 0.017f;
    public float n = 19.70386f;
    public float n_s = 0.013683f; //deg / sec

    public float longitudeOfAscendingNode = 0.0f;
    public float argumentOfPerihelion = 0.0f;
    public float inclination = 0.0f;

    public float M; //Supplies rotation information to the planetary position solver
    public float T;


    GameObject planet;

    EpochTimer timer;

    void Start()
    {

        planet = GameObject.Find("Planet1");

        timer = new EpochTimer();
        timer.SetSystemDate(2000, 1, 0, 0, 0, 0);
    }



    void Update()
    {
        timer.UpdateSystemDate((Time.deltaTime * timeStep), orbitalPeriod);
        T = timer.GetDate();

        M = M0 + n * T;
        M = M - (Mathf.Floor(M / 360) * 360);

        float v = CalculateTrueAnomaly(KepplerSolver(M, 5), 5);

        Vector3 position = new Vector3();
       
        float r = (semiMajorAxis * (1 - Mathf.Pow(eccentricity, 2.0f))) / (1 + eccentricity * Mathf.Cos(v * Mathf.Deg2Rad));

        position.x = r * (Mathf.Sin(longitudeOfAscendingNode * Mathf.Deg2Rad) * Mathf.Cos((argumentOfPerihelion * Mathf.Deg2Rad) + (v * Mathf.Deg2Rad)) + Mathf.Cos(longitudeOfAscendingNode * Mathf.Deg2Rad) * Mathf.Cos(inclination * Mathf.Deg2Rad) * Mathf.Sin((argumentOfPerihelion * Mathf.Deg2Rad) + (v * Mathf.Deg2Rad)));
        position.y = r * (Mathf.Sin(inclination * Mathf.Deg2Rad) * Mathf.Sin((argumentOfPerihelion * Mathf.Deg2Rad) + (v * Mathf.Deg2Rad)));
        position.z = r * (Mathf.Cos(longitudeOfAscendingNode * Mathf.Deg2Rad) * Mathf.Cos((argumentOfPerihelion * Mathf.Deg2Rad) + (v * Mathf.Deg2Rad)) - Mathf.Sin(longitudeOfAscendingNode * Mathf.Deg2Rad) * Mathf.Cos(inclination * Mathf.Deg2Rad) * Mathf.Sin((argumentOfPerihelion * Mathf.Deg2Rad) + (v * Mathf.Deg2Rad)));

        planet.transform.position = position; 
    }


    //Solve Kepplers Equation
    float KepplerSolver(float m, float dec)
    {
        float K = Mathf.PI / 180.0f;

        int iMax = 30, i = 0;

        float delta = Mathf.Pow(10, -dec);

        float temp, F;

        m = m / 360.0f;

        m = 2.0f * Mathf.PI * (m - Mathf.Floor(m));

        if (eccentricity < 0.8f)
            temp = m;
        else
            temp = Mathf.PI;

        F = temp - eccentricity * Mathf.Sin(m) - m;

        while ((Mathf.Abs(F) > delta) && (i < iMax))
        {
            temp = temp - F / (1.0f - eccentricity * Mathf.Cos(temp));

            F = temp - eccentricity * Mathf.Sign(temp) - m;

            i++;
        }

        temp = temp / K;

        return Mathf.Round(temp * Mathf.Pow(10, dec)) / Mathf.Pow(10, dec);
    }


    //Calculate the true anomaly
    float CalculateTrueAnomaly(float e, float dec)
    {
        float K = Mathf.PI / 180.0f;

        float S = Mathf.Sin(e * Mathf.Deg2Rad);

        float C = Mathf.Cos(e * Mathf.Deg2Rad);

        float FAK = Mathf.Sqrt(1.0f - Mathf.Pow(eccentricity, 2.0f));

        float phi = Mathf.Atan2(FAK * S, C - eccentricity) / K;

        return Mathf.Round(phi * Mathf.Pow(10, dec)) / Mathf.Pow(10, dec);
    }

}

Timer

    public void SetSystemDate( int yr, int mo, int d, int h, int m, float s)
    {
        year    = yr;
        month   = mo;
        day     = d;
        hour    = h;
        min     = m;
        sec     = s;
    }
  
    public void UpdateSystemDate(float s, float y)
    {
        sec += s;

        if (sec >= (y * 24 * 60))
        {
            day++;
            sec = 0;
        }

        if (day >= y)
        {
            year++;
            day = 0;
        }

        Debug.Log("Year " + year + " Day " + day + " Sec " + sec);
    }

    public float GetDate()
    {
        int d = 367 * year - (7 * (year + ((month + 9) / 12))) / 4 + (275 * month) / 9 + day - 730530;
        float t = sec / 26309.57f;

        systemTime = d + t;

        return systemTime;
    }
}

Final update for the night. This rig works minus one thing:

The planets jump when a new year starts.

My theory is that it’s because the Epoch calculator is based on an Earth normal 365 day year…in this sim, 1 day is 24 minutes of real time and one year ~ 7 hours of real time (orbital period for the main planet is 18.271 days so that’s my new year).

Here’s the question that I need an answer to: How do I go about creating my own Epoch system? I’ve been looking at the Julian Date Equation:

d = 367y - 7 * ( y + (m+9)/12 ) / 4 + 275m/9 + D - 730530

And trying to puzzle it out…is it as simple as changing the 367 to something more appropriate for my current setting? Is there a scalar I can apply to correct for the new year i’m using? Here’s my timer code…I definitely think it’s the fact that I’m using a 365 day Julian for a 18.271 year…

using UnityEngine;
using System.Collections;

public class SystemTimer : MonoBehaviour
{
    //Initialized to January 1st, 2000, 0:00 UTC
    private int year = 2000;
    private int month = 1;      //1 - 12
    private int day = 0;        //1 - 31
    private float sec = 0;      //0 - 60

    private float systemTime;

    public void SetSystemDate(int yr, int mo, int d, float s)
    {
        year = yr;
        month = mo;
        day = d;
        sec = s;
    }

    public void UpdateSystemDate(float s)
    {
        sec += s;

        if (sec >= 25920.0f)
        {
            day++;
            sec = 0;
        }

        if (day > 17)
        {
            year++;
            day = 0;
        }

        Debug.Log("Year " + year + " Day " + day + " Sec " + sec);
    }

    public float GetDate()
    {
        int d = 367 * year - (7 * (year + ((month + 9) / 12))) / 4 + (275 * month) / 9 + day - 730530;
        float t = sec / 25920.0f;

        systemTime = d + t;

        return systemTime;
    }
}