The simplest game loop can be boiled down to the following.
get_events() we get events from what input devices that we need.
It is important to process events first to prevent lag.
calculate_next_positions we update the game state according to animations and the events captured.
render() we will update the screen and show the game to the player.
A practical example of this is a moving laser bolt.
This game loop works well for consoles and devices where the share of CPU clock speed is always known. The game users will be using the same processor characteristics to run this code. This means that each animation and calculation will happen at the exact same time in each machine. Unfortunately, this is typically not true for modern operating systems and hardware. For faster CPUs and systems with varying loads, we need to regulate updates so that game play will be consistent in most cases.
One way to solve this problem is to regulate the "Frames Per Second" for your game's updates. A "frame" is defined as a complete redraw of the screen representing the updated game state. We can keep track of the number of frames we are delivering each second and control it using the technique illustrated below.
First run the below script with no fps fixing:
You will see that the FPS is erratic, and the laser seems to speed up and slow down randomly.
Next fix the upper bounds of the FPS
perl game_fixed.pl 1
This will prevent the laser from going too fast, in this case faster then 60 frames per second.
Finally fix the lower bounds of the FPS
perl game_fixed.pl 1 1
At this point the FPS should be at a steady 60 frames per second. However if this is not the case read on to the problems below.
Generally, this method is sufficient for most computers out there. The animations will be smooth enough that we see the same game play on differing hardware. However, there are some serious problems with this method. First, if a computer is too slow for 60 fps, it will skip a lot of rendering, and the animation will look sparse and jittery. Maybe it would be better for to set the fps bounds to 30 fps or lower for that machine. However, the developer cannot predict and hard code the best frame rate for a user. Secondly, if a CPU is fast, a lot of CPU cycles are wasted in the delay.
Finally, this method does not fix the fundamental problem that the rendering is tied to CPU clock speed.
One way to fix the problem of a computer being consistently faster or slower for the default Frames per Second set is to change the FPS accordingly. So for a slow CPU, the fps will be limited to 30 FPS and so on. In our opinion, although a consistent FPS can be achieved this way, it still presents the problem of differing animation speeds for different CPUs and systems. There are better solutions available that will maintain a decent FPS across all systems.
The problem caused by coupling rendering to the CPU speed has a convenient solution. We can derive our rendering from a physical model based on the passage of time. Objects moving according to real world time will have consistent behavior at all CPU speeds and smooth interpolation between frames. SDLx::App provides just such features for our convenience through movement handlers and 'show' handlers.
A simple physics model for our laser has a consistent horizontal velocity in pixels per time step at the window's mid-point:
X = Velocity * time step, Y = 100
Assuming a velocity of say 10, we will get points like:
0,100 10,100 20,100 30,100 ... 200,100
Note that it no longer matters at what speed this equation is processed, instead the values are coupled to the passage of real time.
The biggest problem with this sort of solution is the required bookkeeping for the many objects and callbacks we may track. The implementation of such complex models is non-trivial and will not be explored in this manual. This topic is discussed at length in the
This version of the laser example demonstrates the use of movement, 'show' handlers, and the simple physics model described above. This example is also much simpler since SDLx::App is doing more of the book work for us. SDLx::App even implements the whole game loop for us.
To learn more about this topic please, see an excellent blog post by GafferOnGames.com: HTTP://GafferOnGames.Com/game-physics/fix-your-timestep.
Hey! The above document had some coding errors, which are explained below: