0
\$\begingroup\$

Apologies if this is a dumb question I'm still new to this, but I'm trying to understand if calculations of sprite movements/hitboxes/etc. is necessary or is generally better than just using fixed values to calculate movement or events (i.e movement += velocity/framerate vs. movement += velocity/constant).

The main reason I ask is that while following tutorials for basic movements they use the frame rate to determine how to move the sprites, but I haven't seen a full explanation as to why things are done that way. While I was using these tutorials, things seemed to work well, but after I moved past them I've run into odd issues. I'm not sure if that was just because the games in the tutorials were very simple, like pong and breakout, and I just didn't notice these problems.

For example, I made a very simple demo where I take a sprite and have it bounce off the edges of the screen. When it reaches the edge the velocity reverses and it goes in the opposite direction. While the numbers show as correctly calculated, visually it's wrong, either rebounding early or beyond the edges of the screen. However, when I replace frame rate with a constant number it works perfectly. Even when I replace the frame rate with a random value of particular range (say 45-60) it works well. It seems to me on the occasion that the frame rate dips below 30, it throws off everything and doesn't recover.

I've heard about limiting frame rate and that makes sense in a capping the top way, but is limiting it below also something that is done? If so, it doesn't seem too different from just putting in a constant and I wonder what benefits using frame rate even has at that point.

tl;dr: I guess what I'm asking is what are the pros and cons of using frame rate to determine how things move/interact vs using constant values and will it create problems down the line if I try to forgo frame rate completely?

\$\endgroup\$
1
  • \$\begingroup\$ That problem with the ball sounds like a poorly implemented discrete physics simulation. If you can share the code, feel free to post that as a separate question. You might also be interested in continuous physics simulation. \$\endgroup\$ – Theraot Jun 2 '20 at 0:01
3
\$\begingroup\$

No*

* To a first approximation, nothing in games is "necessary". If your code compiles, you can ship it. Whether or not anyone thinks the game is any good is another question.


So, what is scaling by framerate or delta time good for?

It's good if your framerate can change. Obviously, if your framerate is constant, then replacing any framerate scaling with a suitably-chosen constant is equivalent. But there are multiple kinds of framerate change we might care about:

  • Runtime changes: many games render as fast as the hardware can support. That means your framerate can vary between devices, from minimum-spec up to cutting-edge hardware. It also means your framerate can fluctuate during play, if your game is currently processing a heavier-than-normal or lighter-than-normal scene, or if a background process temporarily hogs some of the device's resources.

    In these situations, if you've made all your movement a constant each frame, then in scenarios where your framerate is super high your gameplay runs faster than intended. (Ever play an old DOS game on a modern PC, and everything's just a blur?) And in scenarios where your framerate drops, your gameplay becomes more sluggish.

    This is bad for the player experience, making the game feel inconsistent, and it can even introduce unfairness in competitive games, by giving some players more reaction time or faster responsiveness than others.

  • Development changes: your framerate in the shipped game might well be a constant, but will it be the same constant as at the start of your project?

    Say you were initially aiming for 60 fps, but it turns out by the time you implement all of your features, you can only support 30 fps on your target hardware, so you have to drop your framerate. If all your gameplay simulation uses hard-coded constants, now you have to go re-tune all of those magic numbers to try to get equivalent behaviour at 30 fps as you had at 60. The same goes if you made your game for 60 FPS, and now want to make a VR port at 90 or 120 fps to keep up with player head movement and minimize nausea.

    If you'd coded all your features to scale correctly with the framerate / delta time, even if that value was a constant, now you have just one master constant to change in one place, and most of your tuning should adapt correctly to the new framerate - if you did your math right. Obviously you still need to test and spot-fix, but this can reduce weeks of refactoring to maybe just hours, depending on your scope.

I'd also argue that scaling by framerate / delta time has another useful outcome: it keeps your tuning parameters in intuitive, meaningful units.

position.x += velocity.x * deltaTime;

If position is in tile units and deltaTime is in seconds, then velocity represents tiles per second. This is a nice clear number for a designer to reason about. If I want the player to move 3 tiles in a half-second dash, that's a velocity of 6.

Without the deltaTime, then I have to mentally figure-in the framerate whenever I'm choosing a tuning value like this. For the tile example, well, if we're running at 60 fps, that 3-tile half-second dash is 0.1 tiles per frame. It takes a bit more mental math and imagination to picture the effect of that number.

Now, there are hazards to using a variable timestep in your game simulation. This introduces some non-determinism into your code. Two runs of your game with identical input might not produce exactly identical results, because of small variances in timing leading to differences in rounding, etc.

This can be a point of frustration during development, making it difficult to replicate, isolate, and fix bugs that rely on very precise timing. And it can lead to inconsistencies in play or exploits (eg. deliberately dropping the framerate until you can clip through walls because the timestep has gotten so large that a single movement step teleports you all the way from one side to the other, without ever colliding with the wall in-between)

For this reason, it's often recommended that games use a "fixed timestep" for gameplay simulation:

  • Each simulation step always uses the same, constant timestep (but you still scale by this constant delta time, so that your code and tuning all adapt correctly if you ever change the constant)

  • In order to keep up to the present moment, the game runs the simulation step as many times as necessary to account for the total time elapsed before this frame

  • In order to present a smooth result, any non-simulation-critical effects (eg. UI animations) are scaled to the actual, variable time delta of the current frame, and simulation outputs are interpolated or extrapolated to the appropriate intermediate state.

This gets us the consistency benefits of a constant framerate, with the flexibility, responsiveness, and scaling benefits of a variable framerate, letting our games run predictably on a range of devices under a range of conditions. I present a more in-depth motivation for this convention in this answer.

I've heard about limiting frame rate and that makes sense in a capping the top way, but is limiting it below also something that is done?

Yes. Fixed timestep game loops typically have a maximum number of times they'll attempt to step the simulation in a single frame. So if frames run longer than that, the simulation is allowed to fall behind real-time, so the gameplay can slow down - hopefully giving the device enough headroom to finish whatever heavy processing is hogging the resources, so the game can recover back to its target framerate later.

This avoids a "death spiral" where frames get longer and longer because we keep running more and more simulation steps to try to catch up to real-time on hardware that just can't go that fast.

But it still has the advantage that on more capable hardware, we can run the rendering loop as fast as we want above this minimum cut-off. 500 fps? Sure, if your video card can take it and your monitor can display it, go for it!

For example, I made a very simple demo where I take a sprite and have it bounce off the edges of the screen. When it reaches the edge the velocity reverses and it goes in the opposite direction. While the numbers show as correctly calculated, visually it's wrong, either rebounding early or beyond the edges of the screen.

It sounds like your code has a bug. Post a question about it, demonstrating a Minimal Complete Verifiable Example, and we can help you debug it to get correct behaviour at any framerate.

\$\endgroup\$
2
  • \$\begingroup\$ Ok, so if I'm getting the gist of what you said here (I'll need to go more in depth on reading the links you provided) delta time is most useful for handling different device speeds to provide smoothness across multiple devices. Ok, that does make sense. Also, as I was reading your post I wondered if something like FPS sampling was a thing, where we take an average of them and use that to negate any significant outliers. (That may be the time step you mentioned but I haven't read that yet.) I will see about posting my code, maybe there is a bug, but it seemed so odd it worked ok w/o FPS. \$\endgroup\$ – JGaines Jun 1 '20 at 23:44
  • 1
    \$\begingroup\$ When you test on a single machine, you're getting reasonably consistent behaviour every time. You've effectively baked your development machine's FPS into your choice of constants. Move to another machine that runs faster or slower, and you might find your game feels different. Some engines do attempt to smooth the delta - Unity offers a smoothDeltaTime for this purpose - but most often what we want in games is the instantaneous value. We want to display the correct frame for this moment, however long or short it's been since the last frame, not an averaged-out value. \$\endgroup\$ – DMGregory Jun 1 '20 at 23:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.