Will a "While Loop" Day and Night Cycle be an Issue for my game?

Hi, I’ve been trying to write server-sided code for a day and night cycle for my “restaurant” game that relies on the time to know when the store is open or closed. Currently, I’ve been using a “while true loop” to code this. However, as I do my research, I find that this may not be optimal?

I’m receiving varied responses on how to go about this, and need a clear cut answer. A lot of the tutorial and resources use a while true loop for their cycles, however I’ve come across a post against this, warning it could be very performance heavy.

So, would you recommend using a while loop for a day and night cycle? Reminder that I ALWAYS need time to be changing in my game to get it to work how I want it to be. If not a while loop, what else would you recommend?

1 Like

Here’s the issue: while true will repeat EVERY FRAME. Use while task.wait(amount of seconds it takes to become night) do

If you don’t change the while true do it’ll crash the game (on weaker devices of course).

2 Likes

It’ll wait the amount of seconds and do the thing you told it to do.

Yes, I do have a task.wait() in my loop, but even with that performance will still be demanding, no? My loop has a wait for over 1/30th second, which is very close to 0. I would assume because of this, it’s still performance heavy.

If you are waiting for that short of a timespan, maybe consider using the RunService and attaching it to an event to run every frame. I know you are talking about it being demanding on performance, but RunService will make it cycle smoother at least. I personally think you are better off using the run service when you are doing it ever 1/30 seconds.

RunService only runs on the player, some for that I’m concerned about time-syncing. Also, about the controllability RunService. In my game, I’m looking for the restaurant closing time to last about 4 minutes, and the restaurant to be open for 6 minutes real world. If I have this run service that is uncontrollable the rate it fires, I may not be able to accomplish this.

RunService should properly sync if you use delta time correctly.
Honestly, if you want it to be less resource intensive, just make the wait for the day night cycle longer. Your approach really depends on how realistic you want it to look when it changes.

A while loop is not performance heavy on its own, no.

Think about what roblox does every single frame without you writing any code:

  • calculates movement direction
  • figures out which animation should be playing
  • performs physics updates and determines collisions
  • moves your camera according to user input
  • computes GUI layout
  • renders 3D and 2D scene

Your ten lines of if statements is not going to be the final straw that breaks your processor’s back :slight_smile:

Put it in a while loop with a task.wait, or tie it to RunService.Stepped, whatever works for you.

Write your code so that it solves your problem first and foremost—then you can see if it’s even close to being a performance problem.

1 Like

I see, so taking a look at my code for example (very messy at the moment and equations need to be figured out, but will essentially almost look the same with hundreds of prints for debugging…), all it’s essentially doing is calculating and setting minutes after midnight. Would you deem this performance heavy?

And the thing about solving the problem first, the problem is more of if I should be using a runservice or while true loop. I’m just thinking it would be very helpful to know if a runservice will probably be better, so I don’t end up needing to rewrite the whole system since runservice and while loops run a bit differently.

while true do
	wait()
	if math.floor(lighting.ClockTime) == 0 then
		totalTime = 0
	end
	if lighting.ClockTime >= 0 and lighting.ClockTime < 8 then --once 12am ingame time goes slower (4m)
		while totalTime < closeTime do
			--timeShift = 16/165 -- 1/15 old value
			local deltaTime = task.wait(1/30)
			totalTime += deltaTime
			counter += 1
			--print(totalTime.. " ".. counter) 
			--local minutesshift = game.Lighting:GetMinutesAfterMidnight() + (totalTime*60)
			rate = 480/(closeTime/60) --480/4 480 = 8 hours in minutes, 4 represents end time
			stominutes = (totalTime/60)*rate 
			--print(stominutes)
			--print(rate)
			lighting:SetMinutesAfterMidnight(stominutes)
		end	
		print("reset")
	elseif lighting.ClockTime >= 8 and lighting.ClockTime < 24 then --once 8am time ingame time goes faster (6m)
		while totalTime < (closeTime+openTime) do
			--breaktrue = true
			local deltaTime = task.wait(1/30)
			totalTime += deltaTime
			rate = 960/(openTime/60)
			minusrate = rate*4+(-480)
			roc = ((((closeTime+10/60)*rate)-minusrate) - (((closeTime/60)*rate)-minusrate))/(((closeTime+10) - (closeTime)))
			print("roc is ".. roc)
			intitialvalue = -closeTime*roc
			retainrate = closeTime*(roc)+(intitialvalue)
			print(minusrate.. " and ".. rate)
			print("retainrate is ".. retainrate)
			stominutes = (((totalTime/60)*rate)-minusrate)-retainrate -- we multiply the minutes after midnight by 60 to get the seconds. Divide that by 120 for the conversion giving us total time. , then multiply by 160 for
			print("total time is ".. totalTime)
			print((totalTime/60)*rate)
			print("minutes after midnigh is ".. stominutes)
			lighting:SetMinutesAfterMidnight(stominutes)

		end
	end
	if breaktrue == true then
		print(tick() - starttime)
		print('whole loop broken.')
		break
	end
end

2 Likes

RunService exists in both the client and server. However, you should be doing animation animation-wise on the client. You can have syncing by updating the server at a slower rate and smoothing it over on the client each time it’s updated, or just have a timestamp to base the time cycle on and not have to have the server update even once.

Can you elaborate on the animation part? Does this mean any animation loading and playing should be done on local scripts?

1 Like

Yes, all animations and visual stuff should be handled by the client as much as possible. Roblox’s servers are rather weak. Plus animations look bad when the server handles it anyway. When I say animation, I mean anything that moves rapidly or anything more than just “teleporting”. The server should be used for secure data and client communication only (or as much as possible).

You can use remotes, among other things, to sync animations on each client, or have the client react directly.

Animations that are played on a player’s Character, or are to only be seen by a particular player’s character need to be created and played on that client.

Any animation (other than on a player’s Character) that needs to be seen by all, needs to be played on the server.

Are animations loaded by the server still run on the client? If not, then the client should still be doing that anyway. A remote to all clients can sync the animation. I’ll assume it does make each client animate it instead of the server animating it though, as that would make more sense realistically.

I don’t see anything wrong with a server side loop for the time and day.
Shouldn’t be any sort of performance loss.

local lighting = game.Lighting

local slowSpeed = .5 -- in hours per second
local fastSpeed = 2 --in hours per second

local slowTimeStart = 0 --in clock time
local fastTimeStart = 8 -- in clock time

while true do
	local elapsed = wait()
	if lighting.ClockTime> fastTimeStart then
		elapsed = elapsed * fastSpeed
	else
		elapsed = elapsed * slowSpeed
	end
	lighting.ClockTime = lighting.ClockTime + elapsed
end

1 Like

It is not necessary to sync all clients to an animation, as Roblox will do that automatically when an animation is played on the Server.

That is how NPC’s are handled.

I would still recommend running that on the client as the animator situation is different. If it’s at a slower speed that it doesn’t particularly matter, but if it’s for a constant non-AnimationTrack animation, such as a loop or tween, it would be better to have the client handle it. Both for the purpose of taking any stress it would have off the server, but more importantly, to have a smoother animation.

Like I said earlier in this thread, you could even use a timestamp and not have to use the server at all, while keeping everything in sync.

You are correct, if its something you want to sync to a specific value that the client has, and it needs to be super precise, then yeah, play the animation on the client, according to whatever variable the client is keeping track of.

However, if it doesn’t need to be super precise, don’t worry about playing animations on the server, this isn’t causing undue strain on the server, as playing animations has become really optimized recently on Roblox, and servers are more than capable of playing serve side animations (which in truth are not actually played on the server, but rather the animation data is sent to each client) without causing any strain.

if performance in your loop is bad simply increase the wait time a bit and make the time increments larger (make larger shifts in longer intervals) but otherwise its fine i have written a clock cycle with a for loop before its fine.

while true do runs ALMOST infinitely fast, not every second.