Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
COMMUNITY QUESTION

How can I smoothly transition the time of day without creating inefficient or overly complex code?

I'll show my two different attempted solutions with the drawbacks of each:

A.

while true do

	local minutes_after_midnight = lighting_service:GetMinutesAfterMidnight()

	if minutes_after_midnight > 59 and minutes_after_midnight < 421 then
	    	wait(speed_wait_time)
  	else
	    	wait(default_wait_time)
  	end
	
	minutes_after_midnight = lighting_service:GetMinutesAfterMidnight()
	local new_minutes_after_midnight = minutes_after_midnight ~= 1439 and minutes_after_midnight + 1 or 0

	lighting_service:SetMinutesAfterMidnight(new_minutes_after_midnight)

	if new_minutes_after_midnight == 0 then
	    	day_number = day_number < 7 and day_number + 1 or 1
	    	current_day.Value = days[day_number]
  	end

end

This one works great. It was also the first I made. However, the sun and moon in the sky are jerky in their movement, which is what I want to fix about this bit of code.

B.

while true do

	local current_clock_time = lighting_service.ClockTime
	local new_tween_obj
	
	if current_clock_time > 0 and current_clock_time < 7 then
		new_tween_obj = tween_service:Create(
			lighting_service,
			speed_wait_time,
			{ClockTime = current_clock_time + 1}
		)
	else
		new_tween_obj = tween_service:Create(
			lighting_service,
			default_wait_time,
			{ClockTime = current_clock_time + 1}
		)
	end
	
	new_tween_obj:Play()
	new_tween_obj.Completed:Wait()
	new_tween_obj:Destroy()
	
	if current_clock_time + 1 == 24 then
		day_number = day_number < 7 and day_number + 1 or 1
    		current_day.Value = days[day_number]
	end

end

This one works fairly well, but, depending on the time set for how long the tween will take, the clock on the client will display time inconsistently (i.e. skip a minute or several minutes).

I'd appreciate any fixes, alternative solutions, or advice you have to give. Thanks!

4 comments

0

On roblox's youtube guide for starters has a way of doing it, infact the have a whole episode of it. It was really good and i suggest checking it out.

Good-day!, Narwhal

0

Doesnt :Créate as second argument should be a tween info? from there you can customise the tween.

0

speed_wait_time and default_wait_time are defined as TweenInfo.new(somenumber) and TweenInfo.new(somenumber).

0

That's not what my question's about, though.

2 answers

Firstly, test how much time should an entire cycle should run in real life and then you can convert that to ingame time. For example, Minecraft takes 20 minutes and Terraria 24 minutes, both of them make easy to fit in our 24h clock.

After picking a cycle, you can make a simple equation where every second you sum the "TimeInGame" with a constant. Also, when the "TimeInGame" is >= 24 you can just set the time back to 0. (If you work with minutes, 1440 minutes is the same as 24h)

Here my example I did while learning how to do the cycle with hours, this one there ins't any extra time during sunrise/moonrise or sunset

local hours = 0 --time in hours in the game
local Lightning = game:GetService("Lightning")

repeat
	hours = hours + 0.1667 -- that number is a constant you discover by doing rule of three (i.e 1 minute irl = 1 hour ingame... 1 second irl = X hours ingame)
	game.Lightning.ClockTime = hours --Using time ClockTime because it uses hours
	wait(1) 
	
	if hours >= 24 then --This If makes sure my cycle will not be stuck on 24:00 forever
		hours = 0
	end

until
	hours == 24 --the loop won't stop until it gets exactly at 24h, which will never happen
end

I hope this one gave you a simple idea of how to smooth it.

2 comments

0

That's not a smooth transition because it's changing every second.

0

The value needs to change smoothly from a to b, not go directly from a to b immediately.

To begin with, what I see you're doing is creating a tween, playing it, and only once it has completed doing its thing, you update values such as the current minute, and day.

What we want to do instead, is update these values each frame. We can do this by utilising RunService.Heartbeat:Connect()

Now, if we want to set the actual time, we have 2 ways of doing so: Sync the current time up with the time on the server/client Create a new variable which holds the time

Using both techniques would allow for manipulating the speed that time passes through mid-way, but using the first one is overly complex and not worth it, so we're using a variable instead. In the case of the script that I'm using, Lighting.ClockTime is where we store the variable.

Now, as for changing the time, we will do so using the DeltaTime parameter passed to the function passed to Runservice.Heartbeat:Connect(). I usually tend to shorten it to dt, so I'll call it that for the rest of the explanation.

Now, if we were to simply add dt to Lightning.ClockTime, we'd already have a functional clock, at the speed of 1 hour per second. However, I believe that you want to use a different speed, and be able to change it anytime you wish to.

So, in order to accomplish that, we'll simply multiply dt with the speed we want, measured in hours per second, and we'll change the number we multiply dt with based on conditions that you can set as you wish.

Now, putting all of this together will result in the following piece of code:

game:GetService('RunService').Heartbeat:Connect(function(dt)
	local CurTime = game.Lighting.ClockTime
	
	IsFast = false
	if (CurTime > 0) and (CurTime < 7) then
		IsFast = true
	end
	
	local SpeedMul = DefaultSpeed -- I'm using this setup so you can add more cases for speeding up the time at different paces, if needed.
	if IsFast then SpeedMul = FastSpeed end
	
	 -- This is the part that actually changes the time.
	game.Lighting.ClockTime = game.Lighting.ClockTime + dt * SpeedMul
	
	
	if CurTime + dt > 24 then
		-- This is fired everytime it's midnight, just as happened in your own example
		day_number = day_number%7 + 1 -- This is a faster way to increase a number by 1, and make sure it's in between 1 and 7
		
		current_day.Value = Days[day_number]
	end
	
	-- You can use these for an accurate measurement of time
	local Hour = math.floor(game.Lighting.ClockTime)
	local Minute = math.floor((game.Lighting.ClockTime%1)*60)
	local Second = math.floor((game.Lighting.ClockTime%(1/60))*3600)
end)

1 comment

0

Thanks for the answer! I'll take a more in depth look when I have the time.

This discussion is preserved as it was. New answers, comments, and votes are closed.