Create a Dynamic Day/Night Cycle in Unity

Posted by Gemma Ellison
./
July 7, 2025

It’s time to ditch the static, lifeless lighting in your Unity game. Forget pre-baked shadows and embrace the dynamic beauty of a real-time day/night cycle. This isn’t just about aesthetics; it’s about immersion, gameplay possibilities, and showing off your technical prowess. Here’s how to create a simple, effective system using Unity’s directional light and a bit of C# magic.

Scene Setup: Laying the Foundation

Start with a new Unity scene. Create a Directional Light (GameObject > Light > Directional Light). This will be your sun (or moon). Rename it to "Sun". Position it roughly above the center of your scene. Its initial rotation doesn’t matter too much right now, as the script will control that. Add a simple plane as the ground so you can see the shadows. Add a couple of cubes on top of the ground so you can see the sun moving around them.

Challenge: Many beginners forget to adjust the directional light’s shadow settings. Weak or pixelated shadows ruin the effect. Solution: Increase the shadow resolution and bias in the light’s inspector. Experiment until you achieve crisp, believable shadows.

The C# Script: Orchestrating the Light

Create a new C# script named "DayNightCycle". Attach it to your “Sun” GameObject. This script will handle the light’s rotation and the ambient light adjustments.

using UnityEngine;

public class DayNightCycle : MonoBehaviour
{
    public float dayLengthSeconds = 60f; // Length of a full day in seconds
    public float timeOfDay = 0f; // Current time of day (0-1)
    public float rotationSpeed;
    public Gradient ambientColorGradient;

    private Light directionalLight;

    void Start()
    {
        directionalLight = GetComponent<Light>();
        rotationSpeed = 360f / dayLengthSeconds; // Degrees per second
    }

    void Update()
    {
        // Increment time
        timeOfDay += Time.deltaTime / dayLengthSeconds;
        timeOfDay %= 1f; // Wrap around to 0 after reaching 1

        // Rotate the light
        transform.rotation = Quaternion.Euler((timeOfDay * 360f) - 90, 0, 0);

        //Set Ambient Light Color
        RenderSettings.ambientLight = ambientColorGradient.Evaluate(timeOfDay);
    }
}

This script does the following:

  1. Defines dayLengthSeconds, which determines the duration of a full day/night cycle.
  2. Calculates rotationSpeed based on dayLengthSeconds.
  3. Increments timeOfDay based on the real-time elapsed.
  4. Rotates the “Sun” directional light based on the timeOfDay.
  5. Sets the ambient light color using a Gradient.

Pitfall: Using Time.deltaTime directly for rotation often leads to inconsistent speeds across different frame rates. Using rotation speed, ensures the rotation is consistent.

Setting Up the Inspector: Tweaking for Perfection

In the Unity Editor, select the “Sun” GameObject. In the Inspector for the “DayNightCycle” script, adjust the dayLengthSeconds variable. A smaller value will make the cycle faster.

Create a Gradient object and add it to the ambientColorGradient field in the Inspector. A Gradient is a color range that varies depending on the timeOfDay. Edit it to create color changes from night to day and back again.

Example: Set key colors at 0 (midnight – dark blue), 0.25 (sunrise – orange), 0.5 (midday – light blue), 0.75 (sunset – orange), and 1 (midnight – dark blue).

Optional Polish: Skybox Color Changes

For a more visually appealing effect, you can also change the skybox color based on the time of day.

  1. Create a new Material.
  2. Set the shader of the Material to "Skybox/6 Sided".
  3. Assign 6 textures for the skybox.
  4. In the Lighting window, assign the skybox to the Skybox Material field.
  5. Add another gradient to your DayNightCycle script, called skyColorGradient.
  6. Modify the script’s Update() method as follows:
using UnityEngine;

public class DayNightCycle : MonoBehaviour
{
    public float dayLengthSeconds = 60f; // Length of a full day in seconds
    public float timeOfDay = 0f; // Current time of day (0-1)
    public float rotationSpeed;
    public Gradient ambientColorGradient;
    public Gradient skyColorGradient;

    private Light directionalLight;

    void Start()
    {
        directionalLight = GetComponent<Light>();
        rotationSpeed = 360f / dayLengthSeconds; // Degrees per second
    }

    void Update()
    {
        // Increment time
        timeOfDay += Time.deltaTime / dayLengthSeconds;
        timeOfDay %= 1f; // Wrap around to 0 after reaching 1

        // Rotate the light
        transform.rotation = Quaternion.Euler((timeOfDay * 360f) - 90, 0, 0);

        //Set Ambient Light Color
        RenderSettings.ambientLight = ambientColorGradient.Evaluate(timeOfDay);
        RenderSettings.skybox.SetColor("_Tint", skyColorGradient.Evaluate(timeOfDay));
    }
}

This code snippet sets the _Tint color of the skybox according to a Gradient.

Common Mistakes and How to Avoid Them

  • Flickering shadows: This often happens when the light source’s rotation is too fast, or the shadow bias is incorrect. Lower the rotation speed and adjust the shadow bias in the light’s Inspector.
  • Sudden transitions: Avoid abrupt changes in ambient or skybox color. Use gradients to smoothly transition between day and night.
  • Ignoring performance: Complex lighting calculations can impact performance, especially on lower-end devices. Keep your scene simple and optimize your shadows. Consider using lightmaps for static objects.

This setup provides a solid foundation for a dynamic day/night cycle. Experiment with different light intensities, shadow settings, and color gradients to achieve the desired look and feel for your game. Don’t be afraid to push the boundaries and create something truly unique!