Conflicting Color Tables; Dynamic Clouds

A major issue has occurred with a weather script I am writing. I have made numerous attempts at this point and I seriously hope that this can be fixed. My original post about this error has developed into something slightly different with the post also not getting much attention.

Specifically, I am using dynamic clouds. These clouds change color based on the time (giving a pink hue during dawn/dusk). However, when it rains, I want the colors to change because the clouds look weird when they are very dense but still completely pink.

It should be mentioned that when my time cycle is off (day - night; I tried two different cycles as well as putting them in a local script rather than the original server script), the clouds change properly.

I use a table to achieve the color sets, which seemingly works. To transition to the other tables, I use a tween paired with a math.random statement to randomly pick the cycle. However, when it becomes rainy, the clouds don’t change to the new color table. I have confirmed that the tween and tables are valid. The issue seems to be that the variables are conflicting.

This is one of probably 6 attempts:

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!


TweenService = game:GetService("TweenService")

local min = 20 * 1 -- Minimum time weather is active
local max = 30 * 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
		print('Connected Clear Weather')
		
		local function evalCS1(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
		
		local ClearColors = 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 Update1()
			TweenService:Create(clouds, TweenInfo.new(5), {Color = evalCS1(ClearColors, lighting.ClockTime / 24)}):Play()
		end
		lighting:GetPropertyChangedSignal("ClockTime"):Connect(Update1)
		local ClearWeather = RunService.Heartbeat:Connect(Update1)

	elseif WeatherCycle == 'Rain' then
		print('Connected Rainy Weather')
		
		local function evalCS2(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
		
		local RainColors = 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 Update2()
			TweenService:Create(clouds, TweenInfo.new(5), {Color = evalCS2(RainColors, lighting.ClockTime / 24)}):Play()
		end
		lighting:GetPropertyChangedSignal("ClockTime"):Connect(Update2)
		local RainWeather = RunService.Heartbeat:Connect(Update2)
	end
end

while true do
	Weather()
	wait(math.random(min, max))
	print('Disconnected Weather')
end

This is the original version of the script. It seems to ‘work’, but has the same error.

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))
	print("Line 91 Test 2")
end

I have noticed that when replacing the while loop with a RunService, the color gets stuck in between a purple (test script shows red clouds for clear weather, and blue for rain).

I would much appreciate it if someone can note my issue! I am very bad at scripting so any additional details would be much appreciated.

1 Like

If I am getting this right, you want to Tween the clouds between Clear and Rainy, but have it be darker or lighter based on the ClockTime?

Yes. I have already successfully figured out how to set up the color tables. However, when the script switches to the rainy color table, the color tables do not switch. It seems to work fine when I disable my time cycle. I am confused beyond measurement :skull:

If you need to see a visual, I can create a video!

I think I got it working as you wanted. I found the dev post that you probably used for it, and I went from there.

Try this:

local TweenService = game:GetService("TweenService")
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

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

local trigger

local function Weather() -- Defines weather
	if trigger then trigger:Disconnect() end
	
	local Cycle = {'Clear', 'Rain'}
	local WeatherCycle = Cycle[math.random(1, #Cycle)]
	print(WeatherCycle)
	if WeatherCycle == 'Clear' then -- Sets weather values

		local cloudColors = ColorSequence.new{
			ColorSequenceKeypoint.new(0, Color3.new(0, 0, 0.0156863)),		-- 00:00 (12 AM)  Midnight
			ColorSequenceKeypoint.new(0.5, Color3.new(0.75, 0, 0.0156863)),	            -- 06:00 (6 AM)   Morning
			ColorSequenceKeypoint.new(1, Color3.new(1, 0, 0.0156863)),	    -- 12:00 (12 PM)  Noon
			ColorSequenceKeypoint.new(0.5, Color3.new(0.75, 0, 0.0156863)),            	-- 18:00 (6 PM)   Morning
			ColorSequenceKeypoint.new(0, Color3.new(0, 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

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

	elseif WeatherCycle == 'Rain' then

		local cloudColors = ColorSequence.new{
			ColorSequenceKeypoint.new(0, Color3.new(0, 0.0509804, 0)),
			ColorSequenceKeypoint.new(0.5, Color3.new(0, 0.0509804, 0.75)),
			ColorSequenceKeypoint.new(1, Color3.new(0, 0.0509804, 1)),
			ColorSequenceKeypoint.new(0.5, Color3.new(0, 0.0509804, 0.75)),
			ColorSequenceKeypoint.new(0, Color3.new(0, 0.0509804, 0))
		}

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

		trigger = 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))
	print("Line 91 Test 2")
end

Hang on, changed the wrong numbers

Use this one:

local TweenService = game:GetService("TweenService")
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

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

local trigger

local function Weather() -- Defines weather
	if trigger then trigger:Disconnect() end
	
	local Cycle = {'Clear', 'Rain'}
	local WeatherCycle = Cycle[math.random(1, #Cycle)]
	print(WeatherCycle)
	if WeatherCycle == 'Clear' then -- Sets weather values

		local cloudColors = ColorSequence.new{
			ColorSequenceKeypoint.new(0, Color3.new(0, 0, 0.0156863)),		-- 00:00 (12 AM)  Midnight
			ColorSequenceKeypoint.new(0.25, Color3.new(0.5, 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(0.5, 0, 0.0156863)),            	-- 18:00 (6 PM)   Morning
			ColorSequenceKeypoint.new(1, Color3.new(0, 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

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

	elseif WeatherCycle == 'Rain' then

		local cloudColors = ColorSequence.new{
			ColorSequenceKeypoint.new(0, Color3.new(0, 0.0509804, 0)),
			ColorSequenceKeypoint.new(0.25, Color3.new(0, 0.0509804, 0.5)),
			ColorSequenceKeypoint.new(0.5, Color3.new(0, 0.0509804, 1)),
			ColorSequenceKeypoint.new(0.75, Color3.new(0, 0.0509804, 0.5)),
			ColorSequenceKeypoint.new(1, Color3.new(0, 0.0509804, 0))
		}

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

		trigger = 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))
	print("Line 91 Test 2")
end

This stuff is seriously hard to work with, the testing takes forever. I had the same problem as you’re saying. In the end I gave up on switching clouds and then trying to get things back on the right color cycle it became way too much of a headache.

So what I did was; I found a nice cloud coverage model in the toolbox. Added that to fade in and out with transparency from darker rain looking coverage to invisible. That way I didn’t need to mess with my cloud color cycle at all and could just fade in the the darker clouds when needed as my rain is also random. Worked out perfectly…

Sorry! Got sick, I will be trying your ideas now. Thanks for the help!

I cannot thank you enough! You will for sure be going in the credits with the other amazing people who helped; I have been on this for days!

The amazing dude above managed to get it working (which I plan to figure out his mechanics for sure). I’ve planned to post an advanced lighting cycle once I get the rest of it finished. This is a great idea for sure, but if you are interested in the current mechanism I am using, I’ll be happy to post a link when I publicize it!

1 Like