Smoothly Transition From Cloud Color Cycle to Another?

Hello! I am getting stumped on getting this script to smoothly transition from one cycle to another. As you can see, I am doing a weather cycle, and I have this script for the cloud colors:

if WeatherCycle == 'Clear' then -- Sets weather values
		Rain:Disable()
		
		local cloudColors = ColorSequence.new{
			ColorSequenceKeypoint.new(0, Color3.new(0.0196078, 0.0196078, 0.0392157)),		-- 00:00 (12 AM)  Midnight
			ColorSequenceKeypoint.new(0.15, Color3.new(0.0705882, 0.0705882, 0.0784314)),
			ColorSequenceKeypoint.new(0.22, Color3.new(0.117647, 0.0941176, 0.0941176)),
			ColorSequenceKeypoint.new(0.25, Color3.new(1, 0.360784, 0.360784)),	            -- 06:00 (6 AM)   Morning
			
			ColorSequenceKeypoint.new(0.5, Color3.new(0.784314, 0.784314, 0.784314)),	    -- 12:00 (12 PM)  Noon
			
			ColorSequenceKeypoint.new(0.75, Color3.new(1, 0.360784, 0.360784)),            	-- 18:00 (6 PM)   Morning
			ColorSequenceKeypoint.new(0.78, Color3.new(0.117647, 0.0941176, 0.0941176)),
			ColorSequenceKeypoint.new(0.85, Color3.new(0.0705882, 0.0705882, 0.0784314)),
			ColorSequenceKeypoint.new(1, Color3.new(0.0196078, 0.0196078, 0.0392157))		-- 00:00 (12 AM)  Midnight
		}
		
		local function Update()
			clouds.Color = evalCS(cloudColors, lighting.ClockTime / 24)
		end

		lighting:GetPropertyChangedSignal("ClockTime"):Connect(Update)
		Update()
		
	elseif WeatherCycle == 'Rain' then
		
		local cloudColors = ColorSequence.new{
			ColorSequenceKeypoint.new(0, Color3.new(1, 0, 0.0156863)),
			ColorSequenceKeypoint.new(0.15, Color3.new(1, 0, 0)),
			ColorSequenceKeypoint.new(0.22, Color3.new(0, 0.384314, 1)),
			ColorSequenceKeypoint.new(0.25, Color3.new(1, 0, 0.0156863)),

			ColorSequenceKeypoint.new(0.5, Color3.new(0.784314, 0, 0.168627)),

			ColorSequenceKeypoint.new(0.75, Color3.new(1, 0.117647, 0.117647)),
			ColorSequenceKeypoint.new(0.78, Color3.new(0.686275, 0, 0.737255)),
			ColorSequenceKeypoint.new(0.85, Color3.new(0.482353, 0.301961, 0.933333)),
			ColorSequenceKeypoint.new(1, Color3.new(0.694118, 0.6, 0.0784314))
		}

		local function Update()
			clouds.Color = evalCS(cloudColors, lighting.ClockTime / 24)
		end

		lighting:GetPropertyChangedSignal("ClockTime"):Connect(Update)
		Update()

This works with the function:

local lighting = game:GetService("Lighting")
local clouds = workspace.Terrain.Clouds

-- ColorSequence stuff stolen directly from https://developer.roblox.com/en-us/api-reference/datatype/ColorSequence
-- Bro shoutout to that dude he saved my butt! I did make some edits :) ~ King Noob

-- first and last colors should probably match!

function evalCS(cs, time)
	-- If we are at 0 or 1, return the first or last value respectively
	if time == 0 then return cs.Keypoints[1].Value end
	if time == 1 then return cs.Keypoints[#cs.Keypoints].Value end
	-- Step through each sequential pair of keypoints and see if alpha
	-- lies between the points' time values.
	for i = 1, #cs.Keypoints - 1 do
		local this = cs.Keypoints[i]
		local next = cs.Keypoints[i + 1]
		if time >= this.Time and time < next.Time then
			-- Calculate how far alpha lies between the points
			local alpha = (time - this.Time) / (next.Time - this.Time)
			-- Evaluate the real value between the points using alpha
			return Color3.new(
				(next.Value.R - this.Value.R) * alpha + this.Value.R,
				(next.Value.G - this.Value.G) * alpha + this.Value.G,
				(next.Value.B - this.Value.B) * alpha + this.Value.B
			)
		end
	end
end

I was wondering how I can get these color sequences to smoothly transition from one to another based on if it’s raining or not. Got any tips?

2 Likes

when you set the cloud color in the Update() function, try using a tween instead.
I.E.

TweenService:Create(clouds, TweenInfo.new(8), {Color = evalCS(cloudColors, lighting.ClockTime / 24)}):Play()

instead of

clouds.Color = evalCS(cloudColors, lighting.ClockTime / 24)

Make sure you get TweenService at the top of the script ofc, like so:
local TweenService = game:GetService("TweenService")

This will cause it to interpolate between the last color and new color over the course of 8 seconds.

2 Likes

The TweenService worked perfectly but there is one problem…
My day cycle for some reason isn’t working properly! If the time cycle works, the transition doesn’t and vice versa. This is what I have for the time cycle script:

while wait(0.1) do
	game.Lighting:SetMinutesAfterMidnight(game.Lighting:GetMinutesAfterMidnight() + 0.1)
end

I’ve tried putting it in local scripts and such but it hasn’t worked. Do you know why this is happening?

Here is the local script I tested with:

local lighting = game:GetService("Lighting")
local clouds = workspace.Terrain.Clouds

-- ColorSequence stuff stolen directly from https://developer.roblox.com/en-us/api-reference/datatype/ColorSequence
-- Bro shoutout to that dude he saved my butt! I did make some edits :) ~ King Noob

-- first and last colors should probably match!

function evalCS(cs, time)
	-- If we are at 0 or 1, return the first or last value respectively
	if time == 0 then return cs.Keypoints[1].Value end
	if time == 1 then return cs.Keypoints[#cs.Keypoints].Value end
	-- Step through each sequential pair of keypoints and see if alpha
	-- lies between the points' time values.
	for i = 1, #cs.Keypoints - 1 do
		local this = cs.Keypoints[i]
		local next = cs.Keypoints[i + 1]
		if time >= this.Time and time < next.Time then
			-- Calculate how far alpha lies between the points
			local alpha = (time - this.Time) / (next.Time - this.Time)
			-- Evaluate the real value between the points using alpha
			return Color3.new(
				(next.Value.R - this.Value.R) * alpha + this.Value.R,
				(next.Value.G - this.Value.G) * alpha + this.Value.G,
				(next.Value.B - this.Value.B) * alpha + this.Value.B
			)
		end
	end
end

TweenService = game:GetService("TweenService")

local min = 5 * 1 -- Minimum time weather is active
local max = 6 * 1 -- Maximum time weather is active

local function Weather() -- Defines weather
	local Cycle = {'Clear', 'Rain'}
	local WeatherCycle = Cycle[math.random(1, #Cycle)]

	if WeatherCycle == 'Clear' then -- Sets weather values

		local cloudColors = ColorSequence.new{
			ColorSequenceKeypoint.new(0, Color3.new(1, 0, 0.0156863)),		-- 00:00 (12 AM)  Midnight
			ColorSequenceKeypoint.new(0.15, Color3.new(1, 0, 0.0156863)),
			ColorSequenceKeypoint.new(0.22, Color3.new(1, 0, 0.0156863)),
			ColorSequenceKeypoint.new(0.25, Color3.new(1, 0, 0.0156863)),	            -- 06:00 (6 AM)   Morning

			ColorSequenceKeypoint.new(0.5, Color3.new(1, 0, 0.0156863)),	    -- 12:00 (12 PM)  Noon

			ColorSequenceKeypoint.new(0.75, Color3.new(1, 0, 0.0156863)),            	-- 18:00 (6 PM)   Morning
			ColorSequenceKeypoint.new(0.78, Color3.new(1, 0, 0.0156863)),
			ColorSequenceKeypoint.new(0.85, Color3.new(1, 0, 0.0156863)),
			ColorSequenceKeypoint.new(1, Color3.new(1, 0, 0.0156863))		-- 00:00 (12 AM)  Midnight
		}

		local function Update()
			TweenService:Create(clouds, TweenInfo.new(1), {Color = evalCS(cloudColors, lighting.ClockTime / 24)}):Play()
		end

		lighting:GetPropertyChangedSignal("ClockTime"):Connect(Update)
		Update()

	elseif WeatherCycle == 'Rain' then

		local cloudColors = ColorSequence.new{
			ColorSequenceKeypoint.new(0, Color3.new(0, 0.0509804, 1)),
			ColorSequenceKeypoint.new(0.15, Color3.new(0, 0.0509804, 1)),
			ColorSequenceKeypoint.new(0.22, Color3.new(0, 0.0509804, 1)),
			ColorSequenceKeypoint.new(0.25, Color3.new(0, 0.0509804, 1)),

			ColorSequenceKeypoint.new(0.5, Color3.new(0, 0.0509804, 1)),

			ColorSequenceKeypoint.new(0.75, Color3.new(0, 0.0509804, 1)),
			ColorSequenceKeypoint.new(0.78, Color3.new(0, 0.0509804, 1)),
			ColorSequenceKeypoint.new(0.85, Color3.new(0, 0.0509804, 1)),
			ColorSequenceKeypoint.new(1, Color3.new(0, 0.0509804, 1))
		}

		local function Update()
			TweenService:Create(clouds, TweenInfo.new(1), {Color = evalCS(cloudColors, lighting.ClockTime / 24)}):Play()
		end

		lighting:GetPropertyChangedSignal("ClockTime"):Connect(Update)
		Update()
	end
end

while true do-- Grabs weather values; picks a random time to stay active
	Weather()
	wait(math.random(min, max))
end
1 Like

in a server script, you can just increment clocktime itself.
Like so:

local Lighting = game:GetService("Lighting")

-- there is technically a better way to do this (RunService.HeartBeat)
-- but it's not super necessary.

local SecondsPerHour = 1 -- set super low for testing, I'd set to 60.
while true do
	Lighting.ClockTime += 24/(60*SecondsPerHour)
	task.wait()
end
1 Like

Oddly, I have the same issue. I will post two videos to show my problem.



I made sure to wait over a minute with the time cycle on and I have the same effect. I’m having a hard time figuring out why this occurs. This test is being run with your time cycle (I have also tried the original one I used).

2 Likes

Oops, I sent the wrong video!

2 Likes

Perhaps change it from connecting to ClockTime changed to a simple loop? Updating every x seconds. Also might be worth printing the ClockTime in the Update() function to see if the issue is arising due to that.

Upon looking at the output, it seems to be printing that the cloud color script is still running, but the color isn’t visually changing for some reason. That is very odd, I’m a little lost here :sweat_smile:

In RunService do Color3:Lerp on the colors RGBs with the fraction of (time of day - last time of day) / (target time - last target time)

Every frame in the RunService will provide perfect interpolated RBG values for the time of day as a fraction of the time lapse before it reaches the next target time

Example with Variables needed

  1. TargetTime to Lerp towards
  2. LastTime equal to the last target interpolation time
  3. A Table with the length of the number of cycles and each index is the Target Color
  4. A Table like #3 but it has the Target Time of that color
  5. Cycle variable = to the current index of #3 and #4

local cycle = 1
From fractional time of day 0 to 1 the RunService every frame will calculate:

--Inside a RunService
CurrentTime = TimeOfDay - LastTargetTime


CurrentColor:Lerp(TargetColor, CurrentTime / (TargetTime - LastTargetTime))

if CurrentTime >= (TargetTime - LastTargetTime) then
      if cycle == #TableOfTimes then
           cycle = 1
           LastTargetTime = 0
      else 
           cycle += 1
           LastTargetTime = TableOfTimes[cycle - 1]
      end
      TargetTime = TableOfTimes[cycle]
      TargetColor = TableOfColors[cycle]
end
           
1 Like

This is cool! I will start working on it tomorrow (I am really bad at scripting so I have to spend quite a bit on this). I will be back as soon as I get into this!

From what I understand, this will help me build a color table for each weather cycle? I can pick the table depending on if I want the weather to be clear, rainy, etc, and transition with the script below to get the cloud colors I want?

This will be very fun to mess around with, thanks for the help!

Yes you can do all that if you do some correct coding stuff.

My example was for basically a real time weather cycle so there wouldn’t be anything like a sudden 8 second shift based on a sudden weather event. But if you wanted to do that you definitely could. You’ll want to change the CurrentColor with a Tween to the sudden weather event and then make sure that the RunService is changed to Lerp through the new weather event’s table instead of the one it was using before. So you’ll have to change which Tables the variables are pointing to (to other weather colors and times tables)

The error ran deeper than I knew! All of these ideas has helped me a lot for sure! If anyone has this problem in the future, feel free to check out the official fix: