Comparison of the three versions
The first version of the code, there is no measure of the elapsed time since last update. That would usually make the game frame rate dependent. It is compensated by inserting waiting via
Thread.Sleep, which will give you a fixed timestep on a fast machine. Which is good in that it prevents the render thread to eat CPU time.
By the way, we usually update first to have something to render on the first iteration, also we do not want waits between update and render.
Note: The time the system does not guarantees to preempt the thread for exactly the time you in
The second game loop does not pass the elapsed time either, instead it will let render happen as fast as it can and call update (tick) at a steady frequency, making the game stable. It also includes a simple FPS counter. Advanced FPS counters are beyond the scope of this answer. This version of the game loop is better if you want to debug the render performance (see how fast you can get it to run), however, it is not optimal.
The check of
running before calling render, is there because update (tick) can change
running is not local), and since the call to render happens after, this prevents an extra call. Should not be a problem, assuming teardown happens inside of the stop method. If it were a problem, I would break the loop instead.
About the use of the variable
timer, as you may know, you can simulate timers in the update method by this technique. However, I would recommend to use the approach used for
delta, because it avoids possible overflows on a long run. In fact, you may want to avoid
System.currentTimeMillis because it is susceptible to changing the system clock.
The third code (the one you came up with) will also let rendering happen as fast as it can, and passes the elapsed time to the update method. Yet, it does not control the update rate.
About the naming of delta
In the second version,
delta is an accumulator that is used to decide when to call update (tick). On the last version, it is the elapsed time. Usually
delta means the latter. I have also seen game loops that name the former
delta because it is the time elapsed since the last call to update.
Picking a game loop
Now, should you use a fixed timestep (like the first version), or should you use a variable timestep (like the others)?
The first version
First, the fixed timestep will serve you better if you know the target hardware. As I said, it will prevent the render thread to eat too much CPU, which is good on slow machine, which probably will have a low frame rate also.
Another advantage is that the physic computations are simpler, because you are not taking the elapsed time from the last frame. That also means that any variance in update time will be more noticeable.
However, it may not age well, for instance if you make your game for 30 or 60 FPS when people are expecting 120 FPS.
Thus, if you do not know the hardware, I would advise to make the timestep a configurable option... yet, you would have to take that into account for the update (remember that in the first version, the update does not take the elapsed time).
Not represented on the question
You take the structure of the fixed timestep approach, and still measure the elapsed time from the last update, and still use it to decide if you call update or not... but you may also pass it to the update method.
You would lose the simple physics (which is probably good if your game requires complex physics anyway), you will still be saving CPU time, and you will be accounting for any variance in the update times.
The target timestep is still something you control.
The second version controls the update rate, the third does not
With this version, the game will run as smooth as the system allows it, meaning it will have a render rate as high as possible. It has the drawback of requiring actual physics computations that use the elapsed time.
There is no way to configure the render rate; you may still control the update rate.
If you let the update rate be variable, it can give you problems with fast moving objects, in particular on slow hardware. The elapsed time could mean that objects moved a long distance and you would have to resolve a large amount of collisions per frame, dragging the performance.
While keeping the update rate variable, a common approach is to have a maximum of collision you solve. However, that can lead to objects tunneling through other objects or getting out of bounds. An alternative is to clamp the elapsed time. That would make the game go slower (things move at a lower speed) on slow hardware.
Beyond the game loop
First, do not expect to create a game loop that fits every game. In fact, some games can work perfectly by listening the events provided by the widget library (that is still a loop, but you did not write it). Each game loop has its tradeoffs, and it is a good idea to test and profile on the target hardware.
With that said, here are some other considerations:
For an Android game, you may want to implement a
pause field, that if set, you do not call update. You would then update it according to the activity lifecycle.
You can take advantage of threading, in particular to call subsystems that require more time than one update. The mechanism for this are beyond the scope of the answer.
However, I want to note that threads will compete for CPU time with the game loop, in that case having a call to
Thread.Sleep in the game loop will help, even if only
Thread.Sleep(0). In fact, insert a
Thread.Sleep(0) at the end of the loop, even in the fixed timestep approach, in case the system is too slow that it never reaches the
Thread.Sleep you already had.
Another thing you can do is have the render method be aware of the elapsed time. In particular, if you have a fixed timestep or if you control the update rate, you can compute the time for the next update... with that, you compute the fraction of the time to the next update that has elapsed, and pass it to the render method. The render method would then pass it to the shader as a uniform, allowing animations to happen in GPU. This can give you smooth animation regardless update rate, making them great for the fixed timestep approach... you upload the fraction, the old state and the new state to the GPU, and let it interpolate (fantastic for morph target animation).
Finally, consider breaking the interaction with every external system. Such as getting input, playing sounds, etc. Those are not exactly rendering, and are not exactly updating.