Every game has a game loop. It is a simple loop that should be familiar to every programmer. We can think of a game as a sequence of static images changing fast enough to create an illusion of motion. The purpose of the game loop is to keep generating new frames as long as the loop lasts and, as with any loop, it should not last forever so we must have some way of breaking the loop, usually when a player decides to quit the game.
This is the forth part of the “Kotlin Game Development” series and it’s better if you read it in chronological order:
- Part 1 - Introduction
- Part 2 - Creating a Scene
- Part 3 - Controller Input
- Part 4 - Game Loop (you are here)
- Part 5 - Game Factory
- Part 6 - Main Menu
- Part 7 - Model
- Part 8 - Game Scene
- Part 9 - Finalizing The Game
We’re going to create a class called Game which will wrap the game loop and it will also contain all of the crucial game components such as an input handling module and the current scene.
This class will have two methods:
play - this method will activate the game loop so it can start producing new frames
pause - this method will move the game to the inactive state. The game loop should be stopped which means the game should stop producing new frames
Here is the code:
How Does It Work?
As you can see, the Game class extends the Canvas which is the part of the AWT (Abstract Window Toolkit) library. We can think of the Canvas as the empty drawing space that we’ll be using to draw our game scenes on and because our Game class is also a Canvas we can easily place it inside any AWT window.
The Game constructor takes a single parameter: screenSize, it should state how much space (in pixels) our game wants to occupy. The Game class also has references to the current scene, the input module and the game loop. The play and pause methods are used to control the game lifecycle.
The most interesting part of this class is the content of the game loop, so let’s examine it in more detail:
Before we go into the while loop, we have to initialize the variable called previousUpdateTime. This variable holds the time of the previous iteration and we need to know it in order to find out how much time has passed since the last frame was rendered.
The loop itself will run until the enclosing coroutine is active. Calling the pause method will make this coroutine inactive so it will stop the loop so the code inside it will stop repeating.
In The Loop
The first thing that the loop does is calculating how much time has passed since the last iteration and it can vary from computer to computer. The timePassed value will be larger on slower PCs and lower on the fastest ones. Obviously, the lower, the better but players would hardly notice any difference if the game loop can do at least 30 iterations per second. It would even make sense to cap the maximum amount of frames at 60 per second to make sure we’re not wasting more processing power than we actually need to make sure the game runs smoothly.
Now that we know how much time has passed since the previous iteration we can call the updateAndDraw method to update the game state and draw that state on the screen. We can also obtain a Graphics2D object from our Canvas which can be used by our scenes to perform various drawing operations.
And the last step our loop is supposed to do is to call the BufferStrategy.show method to notify other UI components that the frame is ready to be displayed.
Now we have the game loop, the input module and the Scene class to display our frames. It’s all tied together and managed by the Game class. The only thing our little framework is missing is an actual window. The game needs to live inside a window and that’s what we’re going to implement next.