For very basic things I used a fixed Thread.sleep(20) or such. The processing time is so small, like up to 5 ms, so that
a fixed sleeping time does it. I am speaking of things like Pong or Breakoid and very basic graphics quality.
The second level of timing is the synchronized framerate. You decide on a time per frame, something like 50 ms (20 FPS)
or better. 33 ms for 30 FPS, 20 ms for 50 FPS, etc. Then you take the time at the beginning and end of your game loop
and calculate the time passed, then you go sleep for the remaining time.
Say your game uses 7 ms and your desired time per frame is 20, you would sleep 13 ms. One important thing is, that you at least sleep a few millis, say a minimum of 3 to 5 ms. This gives other threads and garbage collection some time to act.
This method goes down when the pc is too slow and you dont get the frame down in the desired time. The game will then slow down.
The last option is dynamic framerate. At the beginnig of each frame, you take the time. So you can measure the time that passed since the last frame. Then you do all updating based on the passed time. You need to do a sleep of 5 ms or something fixed, and everything else goes as fast or slow as it goes.
The main difference is, with a fixed framerat you can use fixed speed. 5 pixels per frame movement with 30 FPS will always be 150 pixels movement per second. When using a dynamic framerate, you can have more or less FPS and have to do dynamic movement based on the time, so that you end up with 150 pixels per second. You must calculate something like movement per ms and multiply with the ms passed since last frame.
Important: On some Systems, especially Windows, System.currentTimeMillis() is not accurate. You should use System.nanoTime() to take you timing. nanoTime gives you ms * 1.000.000 so in order to get ms times, you need to divide (time2 - time) / 1.000.000.
-JAW