A simple approach to day and night cycles
In games there are several key components, and as a game developer you need to figure out how to implement them. These components are things like weather, saving and loading game state, camera movement, zooming in and out, in-game calendar.. and of course a day and night cycle. Granted, not every game needs these things, but those are the ones I’ve always implemented in tech demos just to get a grip of how they work.
So, the day and night cycle is pretty easily described: time passes in-game as you play, and at some point it gets dark. Our hero now has to endure a night of darkness before dawn and day finally arrives again.
Simple enough. But you don’t want your game to suddenly shift from full bright day to pitch black night. Like in real life you want a gradual transition where it gets slightly less bright, maybe even with a red-ish tint to represent the sun setting. But how?
I’ll tell you how I did it.
For starters, you need a timer.
Assuming you have a working setup with an update loop that receives a delta time, all you have to do is increment the timer by the delta value. This timer represents how much time has passed in-game.
Here’s a simplified example of what I mean:
private double timer;
public void update(float delta)
{
timer += delta;
}
That’s a simple working clock, and with this value you can calculate how many days have passed and also the exact time of the current day.
Next step: decide how long a day should be.
To be exact, you must define how many in-game seconds make up a full 24 hours of your game world time. Let’s say you want one full day to last 5 minutes. Now you can calculate how many days have passed:
public int getTotalDays()
{
return (int)Math.floor(timer / 300);
}
You get the number of days by dividing the total time in seconds by the amount of seconds that make up one day. Even for a math idiot like me, that’s pretty basic.
To get the current time of the day you must subtract the number of days * seconds in one day from the timer value to get the time that has passed since the current day began. I’m sure that could be explained a lot better. I hope you know what I mean. With that value you can calculate the exact hour and minute of a 24 hour clock if you want, but I won’t go into that.
public double getTimeOfDay()
{
return timer - (getTotalDays() * 300);
}
With the basics out of the way, let’s get to the interesting part.
Getting the corresponding tint color of the current time.
You need to tint the screen with a color suitable for the time of day. So, dawn and sunset could be a red-ish tint, night time could be a dark blue-ish and regular day time would just be white. To do that you could map intervals directly in code, something like this:
public Color getDayNightCycleColor()
{
// This will be a value of 0-300.
double currentTime = getTimeOfDay();
// Assuming 0 = midnight.
if(currentTime < 100)
return Color.DARKBLUE;
else if(currentTime > 130 && currentTime < 200)
return Color.WHITE;
else
return Color.DARKRED;
}
This is of course simplified and somewhat pseudo. You would need to figure out the exact values.
However.. that’s actually not how I did it, because what the above method lacks is gradual transitions. You would have night time shift abruptly to red, then from red to white, from white to red and from red to dark blue again. You’d need to work in some gradients somehow, which is totally doable, but you don’t have to if you use my method.
Here’s where my super simple approach really kicks in.
I present you this image (click to enlarge and then zoom in on it):
It’s a map of colors used for the day and night cycle in my game, Factory Magnate. It starts at midnight, then goes through dawn, day time (the 100% white section), dusk and night. If you take a closer look you’ll notice that every stage of the day fades in and out – the aforementioned gradients. Using an image makes it super easy to tweak the duration and color of the different stages.
Oh, by the way, I’m not claiming this method is something new and super clever and never thought of before. I’m sure I’m not the first one to do it this way. Just wanted to get that said and out of the way.
Now, what I do is calculate a float value ranging from 0 to 1 that represents how much time has passed of the current day. So basically it’s a percentage from 0 to 100. And then it’s just a matter of getting the pixel value at that percentage:
public Color getDayNightCycleColor()
{
double currentTime = getTimeOfDay();
float percentage = currentTime / 300; // Again, 300 being the number of seconds in one day.
// Read the pixel of the color map (which you have initialised at some point before all this).
// How you do that varies from platform/engine/framework/etc.
// In LibGDX this is how I do it:
int pixel = colorMap.getPixel((int)(percentage * colorMap.getWidth()), 0);
Color c = new Color();
// Convert the pixel value to a color. Again, how you do that varies.
// In LibGDX this is how I do it:
Color.rgba8888ToColor(c, pixel);
return c;
}
Again, this is pseudo-ish code, I haven’t compiled it. But you should get the gist of the method. The code snippets are pseudo-Java and in this last one I use LibGDX-specific features, because that’s the framework I use. Unless you do too, don’t expect that code to compile.
And that is it! I hope you found it useful.