Get Your Personalized Game Dev Plan Tailored tips, tools, and next steps - just for you.

Create a Dynamic Day/Night Cycle in Godot

Posted by Gemma Ellison
./
July 11, 2025

The subtle shift from dawn’s gentle embrace to the stark coolness of night is a powerful visual cue in games. Forget simplistic, instant transitions; we’re aiming for atmospheric immersion. Many tutorials offer a basic fade-in/fade-out approach. This is insufficient. We need a system that allows for tweaking and fine-tuning, reflecting the unique feel of your game.

Setting the Stage: Our Godot Scene

First, create a new Godot project. Then, create a new scene. A simple Node2D will suffice as the root. Rename it something descriptive, like World.

Add a ColorRect as a child of World. This will be our overlay, responsible for darkening the scene.

Set the ColorRect's anchor_right and anchor_bottom to 1 in the Inspector. This makes it cover the entire viewport.

Importantly, set the Z Index of the ColorRect to a high value (e.g., 10). This ensures it renders on top of everything else in your scene. Otherwise, it will be behind your background.

Finally, create a new GDScript file (e.g., day_night_cycle.gd) and attach it to the World node. This is where the magic happens.

Crafting the GDScript: Code is King

Here’s the GDScript code to control the day/night cycle:

extends Node2D

@export var cycle_speed = 0.01 # How quickly the day/night cycle progresses. Smaller values are slower.
@export var max_darkness = 0.7 # Maximum darkness of the night.  0 is fully transparent, 1 is fully black.

var time_of_day = 0.0

func _process(delta):
    time_of_day += cycle_speed * delta # Advance time based on speed and frame time.  Delta is crucial for consistent speeds.

    # Keep time_of_day between 0 and 1.
    time_of_day = fmod(time_of_day, 1.0)

    # Calculate the darkness based on the time of day.  Using a sine wave for a smooth transition.
    var darkness = sin(time_of_day * PI * 2) * max_darkness

    # Clamp darkness to be within 0 and max_darkness
    darkness = clamp(darkness, 0.0, max_darkness)

    # Modulate the ColorRect's color.
    $ColorRect.color.a = darkness # Only change the alpha (transparency)

Let’s break this down:

  • @export var cycle_speed: This allows us to adjust the cycle speed directly from the Godot editor. A lower value slows down the cycle.
  • @export var max_darkness: This controls how dark the night gets. Experiment with values between 0 and 1.
  • time_of_day: A value between 0 and 1 representing the current time of day (0 = dawn, 0.5 = dusk, 1 = dawn again).
  • _process(delta): This function is called every frame. delta represents the time elapsed since the last frame.
  • fmod(time_of_day, 1.0): Ensures time_of_day stays within the range of 0 to 1, looping the cycle.
  • sin(time_of_day * PI * 2): Uses a sine wave to smoothly transition between light and dark. Multiplying by PI * 2 ensures a full cycle within the 0-1 range.
  • clamp(darkness, 0.0, max_darkness): Ensures the darkness value remains within the allowed range (0 to max_darkness). This is crucial to prevent negative darkness values.
  • $ColorRect.color.a = darkness: This line sets the alpha (transparency) of the ColorRect's color. The higher the alpha, the darker the overlay. We only adjust the alpha to avoid tinting the underlying scene with a specific color (e.g., blue or red).

Customization and Refinement: Beyond the Basics

This is where the real power lies. Don’t settle for the default settings.

Cycle Speed: Experiment with different cycle_speed values. A slower cycle (e.g., 0.005) creates a more gradual and realistic feel. A faster cycle (e.g., 0.05) is suitable for stylized or fast-paced games.

Max Darkness: Adjust max_darkness to control the intensity of the night. A lower value (e.g., 0.3) creates a softer, more subtle night.

Color Adjustments: While we’re only changing the alpha for simplicity, consider also subtly modulating the ColorRect's color. For example, you could add a slight blue tint during the night. This requires more complex code, but significantly enhances the visual effect.

Gradient Mapping: Instead of a simple ColorRect, use a TextureRect with a gradient texture. This allows for far more complex color transitions. You’d need to create a gradient texture that represents the sky color at different times of day. The code would then sample from this texture based on time_of_day. This is advanced, but worth exploring.

Avoiding Common Pitfalls

Frame Rate Dependence: Failing to use delta in the _process function is a common mistake. Without delta, the cycle speed will vary depending on the player’s frame rate, leading to inconsistent behavior.

Z-Index Issues: If the ColorRect doesn’t appear, double-check its Z Index. It must be higher than the Z Index of all other visual elements in your scene.

Overly Harsh Transitions: Avoid abrupt changes in darkness. The sine wave function provides a smooth transition, but you can further refine this by using more complex easing functions.

Ignoring Performance: For complex scenes, constantly modulating the ColorRect's color might impact performance. Profile your game and optimize if necessary. Consider using a shader for even more efficient color manipulation.

Real-World Applications

This day/night cycle is invaluable for creating a sense of time and immersion in your games. Think of open-world RPGs where the time of day influences enemy spawns, NPC behavior, and available quests. Or survival games where darkness presents a significant challenge, forcing players to seek shelter or craft light sources. Even puzzle games can benefit from a subtle day/night cycle to create a more engaging atmosphere.

It is imperative to remember that the key to a good day/night cycle lies in the details. Subtlety and customization are paramount. The provided code is a starting point. A springboard for your creativity. Don’t be afraid to experiment, refine, and tailor it to the specific needs of your game. Make the cycle feel alive. Make it a core element of your game’s experience.