How to shape time however I want?

I’m currently developing some kind of 2D ecossystem with animals, plants etc, and I would like to skip, speed up and down time however I want. How can I do that? I thought about creating some kind of a tick system but I don’t know how to get more than 60 or hundreds ticks per real life second.

Unity uses what’s called a “variable time step.” At the beginning of each frame, the amount of time passed since the beginning of the last frame is calculated (the “delta time” value). This value is then used to update the state of the objects in the simulation. Finally, the state of the simulation is rendered to screen.

One thing you’ll notice about the above approach is that each time you update the simulation (let’s call that a “tick”), you use the amount of real-world time that was measured to have passed since the last tick, and you only do one tick per render. As a result, the game appears to run at a speed equal to real-time.

One thing you could do, rather than calculating the amount of time at the beginning of each frame, is to simply ASSUME that a certain delta time will occur. For example, we might say assume that the delta time for each frame is always 33ms. If the REAL amount of time that passes per tick is greater than 33ms, our game appears to run in fast motion. In the REAL amount of time that passes per tick is less, our game appears to run in slow motion. The problem with this is you can’t choose whether the game runs in slow or fast motion!

The common solution (and my suggested approach) is to disconnect the number of simulation “ticks” from rendering. You can do this fairly easily with a structure like this:

for(int i = 0; i < tickCount; i++)
{
    Tick();
}
Render();

In Unity, Monobehaviors always update once per render, so you’d need to do something like this:

public event System.Action Tick();
private void Update() 
{
    // TODO: Calculate desired tick count
    for(int i = 0; i < tickCount; i++)
    {
        Tick();
    }
}

You might call a Monobehavior like this a “TickManager” or similar. Any other object in your game can use the “Tick” event to update at the correct speed.

The next question is: how do you calculate “tickCount”? That depends on your needs! For example, I had a game where we could only achieve 30FPS on mobile, but we needed to simulate at 60FPS for animations to look correct. So, we did something like this:

accumulatedDeltaTime += Time.deltaTime;
int tickCount = accumulatedDeltaTime / 0.016f; // how many 16ms ticks?
accumulatedDeltaTime -= tickCount * 0.016f;

If your goal is simply fast-forward or slow-motion, you could try to simply tick more or less often. Using the above logic, if your “normal” tick rate is 16ms, you could double that for slow motion or halve it for fast motion. You’d still assume a tick is 16ms, even if you are calling Tick more or less frequently than that! Another method for slow motion is to simply skip ticking in some cases (e.g. skip every odd tick in the tick loop).

If you want to “skip” some amount of time ahead, you simply need to call Tick() enough times in a row before rendering. For example, to skip 60s ahead you could call tick (60 * 1000 / 16) 3,750 times in a row. Of course, you’d need to make sure that your ticks can complete in a very short amount of time for this to work, or you’d have a noticeable performance hitch while doing this loop.

It’s also worth noting that Unity has a “fixed timestep” system that does some of the above logic, if you want to use that. However, I think you get more control over how the logic works if you write something like the above instead.

_
You could use timeScale. By default it’s 1 so if you changed it programatically to 2 then you effectively speed up time (x2 ‘normal’ time) . Setting it to 0.5 would “slow down” time. (x0.5 ‘normal’ time).

Also, re: ticks. Here is how you might “tick” once per second. If you reduced timeScale to 0.5 then it should tick twice per “real life second”.

Update()
{
    if(!ticking)
    {
        ticking = true;
        Debug.Log("Tick");
        yield return new WaitForSeconds(1f);
        ticking = false
    }
}