Run main game loop at 30 fps

On the serverside, I’m currently running my main logic loop at 60 fps using Heartbeat. My main script looks something like this:

RunService.Heartbeat:connect(function()
	UnitData:Loop()
end)

If a loop takes more than one Heartbeat cycle, then my game starts to slow down. I’m wondering if it’s possible that my game could run at 30 fps and hence, each loop would be given twice the amount of time to do whatever computations are needed (is it possible to spread out the loop over two frames, and what is the best way to do this?). I’ve thought of using a coroutine/spawn, then having it be triggered once every two Heartbeat cycles; however, I’m wondering if there’s a better way that this can be accomplished.

2 Likes

You could use the deltaTime parameter of a Heartbeat connection to try and force your game loop to only run at 30 fps. Just add it up, and if it gets over a thirtieth of a second then reset it and call the :Loop() function. Quick (untested) mockup of what it could look like:

local timePassed = 0

RunService.Heartbeat:connect(function(deltaTime)
	timePassed = timePassed + deltaTime
	if timePassed > 1 / 30 then
		timePassed = 0
		UnitData:Loop()
	end
end)
2 Likes

Then you need to optimize your loop code, as it apparently isn’t completing its job within the allotted time - and which is why you experience this “game starts to slow down.”

You cannot even be sure of, that Heartbeat is fired 60 times a second. According to the documentation; “it runs on a variable frequency.”

Whatever your UnitData:Loop() does, if it is supposed to be closely tied to a “game tick”, then you must specifically ensure that that code (including everything else connected) runs in less time (i.e. extremely fast) than before the next “game tick” occurs.

In case you cannot guarantee nor make your UnitData:Loop() run in less time, then you should most likely not tie it to the RunService’s frame-rate.

There are many ways to “spread out” code execution, but without knowing exactly what you have in that UnitData:Loop(), here are only some generic suggestions:

  • Don’t loop through each-and-every-item-in-an-array every frame, if not specifically needed. - Spread out the load, so only / maximum N items will be processed per game-tick, while keeping track of “the current item index” so at the subsequent game-tick it can continue from that point of, until all items in the array have been process, when it then can “wrap around” and start again from the start-of-array.

  • Do you really need to execute “this entire code” (whatever it is) at every game-tick? How computational heavy is “this code”, and could it possibly be split / broken up into smaller individual sequential computations (put into functions/methods/…), which will be easier to “spread out” across several game-ticks?

3 Likes