The naively ambitious starting point for this project was the idea for a space farming game, wherein the player must manage an interplanetary farming supply chain at relativistic distances and speeds. The core mechanic would involve deciding when to send off your ships at how fast such that they return from their voyages, time dilation and all, with a full harvest of crops.

Pretty early on I encountered two glaring problems with this idea. To start, a game centered around logistics management combined with astrophysics must have such a small niche that it might not even exist, but more importantly I realised that I hadn’t wrapped my head around time dilation enough to do anything productive with it. I needed to approach the concept in a much smaller way first.

I scoped back and tried to start visualising time dilation in a more approachable (and manageable) way. An Intro To Special Relativity helped me begin to grasp at the concept, and at the very least provided the mathematic foundation to start putting something together in Unity.

The google image result for “Time Dilation”. Not particularly intuitive.

The Universe

public class Universe : MonoBehaviour
{
    public static float c = 2;
    public static float InverseGamma(float v)
    {
        float y = 0;
        y = Mathf.Sqrt(1 - Mathf.Pow(v, 2) / Mathf.Pow(c, 2));
        return y;
    }
}

The class above controls the laws of physics for my simulation. c is the absolute maximum velocity in the world (speed of light), which is very low for the sake of demonstration. InverseGamma() is the equation that describes time dilation, or the Lorentz transformation. In this case, because all of our scripts run on the observed objects and not the observer (more on that below), we use the inverse transformation.

Controlling Time

public class TimeController : MonoBehaviour
{
    float velocity;
    Vector3 pPosition;
    public float localTimeSinceStart = 0;
    
    void Start()
    {
        pPosition = transform.position;
    }


    private void FixedUpdate()
    {
        //Calculate velocity in units per (realtime) second:
        Vector3 vel = this.transform.position - pPosition;
        vel /= Time.fixedDeltaTime;
        velocity = vel.magnitude;  // Units per RT second;

        pPosition = transform.position;

        //Acculmulate local time elapsed
        localTimeSinceStart += GetDilatedInterval(Time.fixedDeltaTime);
    }

    public float GetDilatedInterval(float observerTimeElapsed)
    {
        //In the reference frame of /THIS/ object, the 
        //transformation is the INVERSE of the observer's reference frame.

        //i.e. we have to inverse the dilation equation 
        //to get what the time is from this object's 
        //perspective, relative to the observer.
        return observerTimeElapsed * Universe.InverseGamma(velocity);
    }

The TimeController class controls the timing functions of the simulation. Each object that can move has this script attached. The script will calculate and store what the time since the start of the simulation is for that object, from the observer’s perspective (i.e. relative to the object at rest).

To calculate the ‘local’ time, we use Unity’s physic simulation tool, fixedDeltaTime. Unlike the standard “Update()” loop which is subject to variable framerates, “FixedUpdate()” runs on a separate thread and guarantees a fixed interval between its cycles. This is good for simulating physics in general, and in this case I’ve used this fixed time as my ‘quanta’ from which all other time is based. A single interval of the fixed loop is stretched out (via the Lorentz transform) for the objects which are moving quickly.

This script replaces the standard Time class for the Unity game engine. For instance, if an object is supposed to change colour after 5 seconds have elapsed, instead of retrieving Time.realTimeSinceStart, we can query this.TimeController.localTimeSinceStart.

Managing Events

There is a definite liberty that we are taking with this whole situation. If the speed of light is low in this universe, we as observers would only be seeing the light from these events much later, and the idea of simultaneity would immediately break down (as it does in our universe at interplanetary distances).

To work around this, I have situated us, the observers, as extra-dimensional beings not subject to the slow speed of light or any of the other laws of physics. There is a sort of aether we see (the ‘scene view’) in which things do, absolutely, at a specific time, happen.

To try to visualise the actual laws a bit more appropriately, I have set up “events” that happen according to each object’s own internal (local) clock. Each object has a ticking hand that revolves around it once each of its own seconds. Every revolution of the hand (so every local second) the object emits a ‘light pulse’ in the direction of the observer at rest within the world.

To try to further highlight the time stretching, each object cycles through a range of colours and the light it emits reflects it colour at the time of emission.

public class EventPulse : MonoBehaviour
{
    [SerializeField] float eventInterval = 5f;    // In local time
    [SerializeField] GameObject lightBeam;
    [SerializeField] Transform pulseTarget;

    TimeController timeController;
    ColourOverLife colourOverLife;

    float lastEvent = 0;
    
    void Start()
    {
        colourOverLife = GetComponent<ColourOverLife>();
        timeController = GetComponent<TimeController>();

    }

    private void FixedUpdate()
    {
        if(timeController.localTimeSinceStart - lastEvent > eventInterval)
        {
            EmitPulse();
            lastEvent = timeController.localTimeSinceStart;
        }
    }

    private void EmitPulse()
    {

        Vector3 toObject = pulseTarget.position - transform.position;
        GameObject pulse = Instantiate(lightBeam, transform.position, Quaternion.LookRotation(toObject));

       //Set pulse colour to object colour:
         pulse.GetComponent<Lightbeam>().SetColour(colourOverLife.emissionColour);

    }
}

So only once the beam of light emitted from an object reaches the observer will the observer have any information about that object (at the “time” that the object’s light left it).

The colours of each object cycle through this spectrum:

The Future

There are two next steps I’d like to take before considering how to gamify this manageably:

  1. Implementing length contraction. Similar to time dilation, in that it involves the Lorentz transformation, length contraction is a bit trickier to implement in Unity. Unity’s time system is easy to access but the space system (the “Transform” class) is a bit more beholden to our nonrelativistic view of the world. I’d like to put more thought into how to visualise length contraction.
  2. Visualising what the “Observer” sees. I wonder if there’s a way to render out the view from the observer, given the ‘lightbeams’ that it is receiving. Perhaps there is a ‘relativistic renderer’ somewhere in there!