2
\$\begingroup\$

I've been reading up how to lay out a game loop that'll work optimally in both great and not so great conditions but I think I've confused a few techniques together... so I have some questions...

  1. Fixed Physics Step: If I fix my physics step because determinism is important in my game, and at some point the game falls behind and needs to catch up, would I need to update multiple times or is there a safe method of updating physics by double or triple steps? If I'm rolling my own physics should I write them in a particular way to facilitate this?
  2. Input: If I need to update multiple times before the next frame should I check the input before updating each time or check once and leave the input for the next tick after that to handle?
  3. Updating: How often do I really need to update a game so no lag is felt by the player? It seems like you can get away with well under 60tps but at what point do players feel the delay? Are there any drawbacks to updating less frequently than rendering?
  4. Networked: If the game is networked through an authoritative server, would all machines have to update their client side predictive movement code at the same rate as the server to avoid constant visible repositioning or would the difference be minimal and virtually undetectable if I resolve potential jittering with smooth position correction?
  5. Interpolation: Would interpolating the position of drawn objects between updates be something I'd only need to do if my game updated at a much slower rate than my fps or is it good to interpolate anyway? What would interpolating involve? Running another partial position update just before the draw or updating the next position in advance and using the partial step percentage (time passed sine last update) to advance positions that percentage between the current and next steps?
  6. Render Timing: Is there a way (or a need) to draw a frame at the last moment before the screen refreshes?
  7. Sleeping: After a draw when I don't yet need to update I should hand the thread back over to the OS, yeah? If I'm making a cross-platform game and some operating systems might wake my thread up a little earlier or later than I've specified is there a chance that might affect the game at all if my physics is fixed?
\$\endgroup\$
  • 2
    \$\begingroup\$ Sorry, but I can only answer 5 of your 7 questions well, so I can not post an answer which would be complete. So I will not answer at all. Please consider to split your question into multiple separate questions. \$\endgroup\$ – Philipp May 3 '15 at 11:44
  • \$\begingroup\$ @Philipp, 5 out of 7 is not too bad. You should still write an answer. Someone will eventually show up and answer the other 2 points. \$\endgroup\$ – glampert May 3 '15 at 17:14
  • 1
    \$\begingroup\$ For 7. You usually roll your own platform-dependent exact sleep function. \$\endgroup\$ – akaltar May 3 '15 at 19:30
2
\$\begingroup\$

I'll answer multiple related questions at once, because it's easier to understand when everything related is at one place.


The best way your game loop can be implemented is to have constant game speed and variable FPS. Note that this does not mean it's the easiest way. Why is it so and how it can be implemented is nicely described in deWitters article, I'll just post a quick overview.

Note: 'Update FPS' is basically 'Game speed' from deWitters article

Updating (1., 2., 3.)

In short, your game loop should call update_game() at constant manageable rate, say 25FPS (as in deWitters article). The reasons why your game speed should be rather lower than higher are, that it:

  1. Assures game runs smoothly on slower hardware
  2. Prevents big floating-point-number-calculation-inaccuracy by simply lowering the frequency of calculations.

Note that handling user input is one of those things, which should be handled in update_game() as well, (among the aforementioned physics handling). 25FPS for input is pretty good.

As it was mentioned before, in this case, your physics computations will always "catch up", there will be no need for doing multiple calculations. Simultaneously, your independent rendering part render_game() can run at 60FPS with some drops, while having no negative effect on handling physics.

As to the question of special care for your physics handling - in this case, you're using constant update FPS => NO.

Interpolation (3., 4., 5.,)

If you only read the updating part of this answer and went for the implementation right away, you'd notice that you would be getting nice rendering FPS and always constant update FPS, but the movement would be jerky. That's because the data is still updated only 25FPS! This is when the interpolation comes in.

In render loop, you can predict where, let's say a ball, should be in this particular moment based on the current (means calculated the last update frame) position, velocity, orientation and delta time from the last updated frame. This is what we would be doing in the update_game() (however, we would add here some other things as well, for example collision detection) if we had unlimited or very high update FPS. Sure, the drawback of inaccuracy is still there even in render_game(), but it's not that big, because:

  • We are calculating the data at the moment from last 1/25th of second, which is pretty accurate.
  • All the heavy-stuff like collision detection is gone. Player won't notice that your ball went a bit behind the wall for less than 1/25th of second

Implementation

I'll just use the ball example and I'll use the example implementation from deWitters article. You have to check it out, it's all there.

Something like this would be in your update_loop() (ignoring collision detection and stuff like that)

position = position + speed;

And something like this in your render_loop()

view_position = position + (speed * interpolation)

where interpolation is a value between 0.0 and 1.0 and represents the progress between two update_game() calls.

Rendering (6.)

Using the constant game speed and variable FPS strategy, you are rendering frequently enough not to have to worry about this. Anyway, games often use so-called double-buffering, which basically means that one frame is being drawn to the screen and the other is being written to the buffer, based on the current data. After that is completed, they swap (= change their roles). This means that you always see things one frame late, but that is no big deal.

As for the question itself, we are interpolating and we have separate update and render loops, remember? It's the most accurate method I know of.

Networking (4.)

Here, you always have to interpolate, even in the update_loop(). You won't be probably getting data every 1/25th of second, not to mention lags. Which means, that if you don't now the things at the moment, predict them. You have no better shot.

Sleeping (7.)

You have 2-priority game loop:

  1. update_game(), gets called at least 25 times per second
  2. render_game(), gets called either as frequently as it can, or it has some upper limit, let's say 60 FPS

If we have the latter case, we can take the rest of time and let the computer "sleep". Chances are that this won't be exact, but based on what you used, it may be exact enough. In most cases, however, this will not affect your update loop.

\$\endgroup\$
1
\$\begingroup\$

to 1, 3, 7: I assume by "the game falls behind and needs to catch up" you mean, your update-rendering cicles are taking more time than they should, depending on the desired UPS and FPS length. In that case: In the methods for updating physics I know, the physical behavior changes when you change the deltaT time step. This would mean, if you simply take the passed time since the last update call for deltaT, falling and bouncing objects would behave different all the time, and the physics in your world would constantly change.

So the deltaT taking into calculation should always be the same. You could devide the passed time into segments of the size of your desired deltaT and the call the physical update multiple times "to catch up", as you said. In my cases rather always used the same deltaT and wrote my game loop in a way, that preferred updating over rendering, because there was never any reason to render, if I didn't update the physics. I would have drawn the exact same image like before. Furthermore, each game loop round (update+rendering) was desired to have a consant time to avoid further complication.

my gameloop basically is:

  • get the time span, the previous loop round took till now, consider the previous round might have taken too long or was too short. Use this span and the desired round length, depending on the set fps to determine, when the current round should end. The ending time would be the time it would have taken for the previous round and the current round to end regularly, taking the exact desired time. Therefore, current round might be desired to be a little longer or shorter than the previous one to meet this case.

    cycleEndTime = TimeNow() + cycleLength + getLeftTime(cycleEndTime);

  • then, update physics (no matter what)

  • check, if this cycle still got time. If not, skip drawing and continue with next loop round. I can skip for at least 6 times, before I can notice a skip in drawing with my eyes in 60 fps.

  • after drawing, if still got time, Thread.sleep till cycle end. If, like you wrote in 7., the sleep is woken up too soon, I will detect this this in the described manner for calculating cycleEndTime and the upcoming loop round would be taking up the time by being longer.

So when changing the FPS and thereby the desired length of a loop round, the game would be updated more frequently in the same "viewer's time". The physics would be updated more often in the same time, objects would move faster, but the physical behaviour ittself would not change due to constant deltaT.

\$\endgroup\$

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.