Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
1

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

Asked by 4 years ago
Edited 4 years ago

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!

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 NarwhalAndMe 141 — 4y
0
Doesnt :Créate as second argument should be a tween info? from there you can customise the tween. User#24403 69 — 4y
0
speed_wait_time and default_wait_time are defined as TweenInfo.new(somenumber) and TweenInfo.new(somenumber). User#26971 0 — 4y
0
That's not what my question's about, though. User#26971 0 — 4y

2 answers

Log in to vote
0
Answered by 4 years ago

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.

0
That's not a smooth transition because it's changing every second. User#26971 0 — 4y
0
The value needs to change smoothly from a to b, not go directly from a to b immediately. User#26971 0 — 4y
Ad
Log in to vote
0
Answered by 4 years ago

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)
0
Thanks for the answer! I'll take a more in depth look when I have the time. User#26971 0 — 4y

Answer this question