Setting FPS
-
I am encountering unavoidable slowdown in my project, and I would like to limit it to (e.g.) 30fps to have extra time each frame.
Is the best way to do that similar to the example code shown for the time() function? Namely, at the end of each frame, make the program "wait" until 1/30 of a second has passed?
(I tried with the sleep() function, but that resulted in more showdown)
-
The following should do the trick, but the fps number indicator does not seem to be influenced by the sleep command:
int fps = 30 loop sleep((1/fps) - deltaTime()) update() repeat
-
I'm not entirely following what you are trying to acheive because using sleep won't give you any extra usable time since Fuze will just sleep during that time and you won't be able to do anything. Although the technical answer I was given wasn't quite this straightforward, you should consider that
update()
will automatically wait for the next vblank if you want to use old-school terms. But that's only really of any consequence if you have any spare time left which it sounds like you don't.I think I get what you want, and the simple answer is that I don't think you can do it. The example in the help for time is allowing you to wait for a period of seconds to pass and that's certainly not what you want.
-
@PB____
I like how you've done that it's very clever -
@Martin
Originally I read the question the same way. I did notice that FUZE doesn't completely pause during a sleep command (you can still use + to close the game, and the FPS numbers keep refreshing). But I didn't assume that FUZE would schedule garbage collection tasks during a sleep command, or anything fancy like that.However, if the performance of your game varies between 30 and 60 fps all the time, then the user may notice performance issues. If you cap the fps at a consistent 30 fps, then the user gets used to it for the game and have a better user experience overall. So on second thought, I assumed this was the nature of the original question :)
-
@PB___ Thank you for your code snippet! It makes sense, and I look forward to trying it when I am on front of my Switch.
And you summarized my issue well: Rather than let the game fluctuate between about 45 and 60 fps (depending on things like how many enemies are present), I thought "pinning" the rate to 30 fps would be smoother. I saw that suggested on another thread, but could not find that nor how to implement.
-
Found out something that might help if it's not too late. FUZE buffers at least one frame. By 'buffer', I mean that there is a queue. If you're pumping out 60 FPS with ease, you'll have the frame you're currently working on and the one being displayed; but in between those, there can be at least one waiting to be displayed. When you call update(), your current frame doesn't get displayed. You do have to wait for the next vertical sync, but when that comes, only the frame from the queue gets displayed, your then current frame goes to the queue, you get given back control and can work on the next frame. Given that we can get tearing free 45 FPS, I suppose it's just fully triple buffering all of the time? That would make sense, it's definitely a very beginner friendly setup.
What this means is: If you do nothing every other frame, you can achieve a solid lock to effectively 30 FPS (FUZE will happily display 60 because it counts the empty frames, too, and the frame time graph will go a bit crazy)
loop float dt = deltaTime() // empty frame update() dt += deltaTime() // dt will now be 1/30 in the best case clear() // do usual work, using dt as timestep update() repeat
Or more robustly, you can do all or some of your non-rendering tasks during the empty frame. This requires a bit more care with the deltaTime since you need a good value during both steps:
float dt = 1/30 loop float nextDeltaTime = deltaTime() // do computational only work, using dt as timestep update() nextDeltaTime += deltaTime() clear() // do rest of the work, still using dt as timestep update() dt = nextDeltaTime repeat
Other schemes may work, too. Key is to call update() one extra time per iteration with no preceding draw calls and take care to collect all deltaTime() values.
Needless to say, this relies on undocumented behavior. It's not clear that an empty update() call doesn't cause issues (inserted black screens, for example), and the frame buffering behavior can also change.
-
Interesting post, thanks.
-
@Z-Mann Thank you for this idea! It makes sense. I think I ran into this buffer queue sideways when I tried the approach @PB_____ suggested above. Somehow, I was not able to figure out the "right" dt to correctly get a "do-nothing" frame.
I actually tried something similar to your suggestion, the division of computation and rendering across two frames. Unfortunately, I messed it up and got "flashing" back and forth between blank frames and my scene. I think I will try again - it seems like the most promising approach, as far as I can understand right now!
-
In my game, I'm not quite hitting 30 fps. Would I gain anything by using the pattern in @Z-Mann's answer above?
Currently I cannot fit both the calculations and the drawing command in the 1/30 seconds that would be necessary for a stable 30 fps frame rate (I'm currently hitting about 22-28 fps) . But if I do all calculations in one 1/30 second frame, call update(), and then do the drawing in the next, would I be able to get to more stable frame rate that way?
-
Also, @Z-Mann, could you (or someone else) perhaps elaborate a little bit about the difference between timestep and delta time, and when and how to use which?
-
@vinicity Delta Time and Timestep are used mostly interchangeably. Mostly! Delta Time refers more to the measured time of a frame (that would be why deltaTime() is the name of the function), while Timestep is the value you use to advance your game world, as in
timestep = deltaTime() x = x + v * timestep
for simulating linear movement with speed v. Normally, those would be equal. But if you apply a fast forward or slow motion effect, you put a factor in between the two, as in
timestep = deltaTime() * 2 // fast forward at double speed x = x + v * timestep
Or, sometimes it's necessary to calculate the game advancement between two render frames in two simulation steps:
timestep = deltaTime() * 0.5 x = x + v * timestep x = x + v * timestep
That doesn't make sense in this simple example, of course, but racing games sometimes do this to accurately simulate suspension and ground traction.
Here, you have the opposite situation, you do one game update per several 'render' frames.
I don't think you get any advantage from the two step scheme if you never ever hit 30 FPS. Only if you have large frame-to-frame variance in processing/rendering time, it might help to flatten the bumps a bit. But the scheme should totally be extendable to three frames to try and lock to stable 20 FPS, if that's a framerate your game is still playable at. You need to distribute the work, then, the buffering only gets you so far. So (adopting the timestep variable name)
float timestep = 1/20 loop float nextTimestep = deltaTime() // do computational only work, using timestep update() nextTimestep += deltaTime() // do some more computational only work, using timestep update() nextTimestep += deltaTime() clear() // do rest of the work, still using timestep update() timestep = nextTimestep repeat
-
Thank you for the explanation. Very interesting, indeed. I have never really thought about or used these concepts before.
-
Alright, I've taken another try with it! I tried the "split frame" approach again. However, the optimal division of work still eludes me: In my main test case, I am somehow still not keeping up with the frame rate.
So... I am broadening the discussion a bit to ask a related question: How "expensive" are certain functions compared to others? Are there "known" bottlenecks to be careful of?
One thing I tested last night was object groups. In my Starfighter game, I use object groups to make a custom camera. In a small test program, I set up an array of 200 randomly moving objects, testing for collisions between each pair with objectIntersect. If I place all 200 objects in a group, I got around 13fps. If I did not put the objects in a group, I got closer to 15fps. I thought that was an interesting find.
My next idea is harder to test with a simple program, so I thought I would ask here: In a long program file (>1000 lines), is there a "penalty" for calling functions from opposite "ends" of the program?
-
You could probably also do
myTimer = setTimer(1/30, -1, functionName) // Stuff function functionName // Some other rendering-related code update() return void
It might not suit every situation, but it's worth a thought.
I'm not sure about the -1 though, but it worked for my tests, and it should last for over a hundred hours at least, even if the timer can run out 🤔
-
That’s an interesting approach, and seems easy enough to try.
-
DaddyJDM: Apparently, it is known that FUZE is not fast with multidimensional arrays. Other than that though, I dunno. I often wonder about things like that myself, what’s expensive and what’s not etc.
Like, there’s a ‘distance’ function in FUZE, which is generally known to be expensive because to get the distance between vectors, part of the way to do it is to use square roots, which is expensive. Maybe because it’s a built-in function though, it’s not too bad. Also, am I slowing things down by using really long variable names? I dunno!
-
@toxibunny the interpreter probably at least tokenizes your code. I wouldn't worry about names (but I could be wrong)
Built-in functions also run at native speeds from what I can tell so they can probably also be safely used at will.