A Basic Game Architecture
The following diagram represents a game architecture.
In the schema above you see the Android OS running on the Phone and everything on top of that.
The input is the touch-screen in our case but it can be a physical keyboard if the phone has one, the microphone, the camera, the accelerometers or even the GPS receiver if equipped. The framework exposes the events when touching the screen.
The User Input
In our game this is the event generated by touching the screen in one of the 2 defined control areas.Our game engine monitors the onTouch event and at every touch we record the coordinates. If the coordinates are inside our defined control areas on the screen we will instruct the game engine to take action. For example if the touch occurs in the circle designated to move our guy the engine gets notified and our guy is instructed to move.If the weapon controller circle is touched the equipped weapon will be instructed to fire its bullets. All this translates to changing the actors’ states that are affected by our gestures aka input.
Game Logic
The game logic module is responsible for changing the states of the actors in the game. By actors I mean every object that has a state. Our hero, droids, terrain, bullets, laser beams etc. For example we touch the upper half of the hero control area like in the drawing and this translates to: calculate the movement speed of our guy according to the position of our movement controller (our finger).
In the image above the light green circle represents our finger touching the control area. The User Input module notifies the Game Engine (Game Logic) and also provides the coordinates. dx and dy are the distances in pixels relative to the controller circle centre. The game engine calculates the new speed it has to set for our hero and the direction he will move. If dx is positive that means he will go right and if dy is positive he will also move upward.
Audio
This module will produce sounds considering the current state. As almost every actor/object will produce sounds in their different states and because the devices we’ll run our game on are limited to just a few channels (that means briefly how many sounds can the device play at once) it has to decide which sounds to play. For example the droid posing the biggest threat to our hero will be heard as we want to draw attention to it and of course we will need to reserve a channel for the awesome shooting sound of our weapon as it is much fun listening to our blaster singing. So this is the audio in a nutshell.
Graphics
This is the module responsible for rendering the game state onto the display. This can be as simple as drawing directly onto the canvas obtained from the view or having a separate graphics buffer drawn into and then passed to the view which can be a custom view or an OpenGL view.
We measure the rendering in FPS which stands for frames per second. If we have 30FPS that means that we display 30 images every second. For a mobile device 30 FPS is great so we will aim for that.
The only thing you want to know now that the higher the FPS the smoother the animation. Just imagine someone walking and close your eyes for exactly one second. After opening your eyes you will see the person in the position after one second. This is a 2FPS. Watch them walk but keeping your eyes open and you’ll see a fluid motion. This is guaranteed to be a minimum of 30FPS but it is likely to be more, depending on your eyes. If you have awesome receptors in pristine condition this could be 80-100 or more.
Output
The output is the result of both sound and image and maybe vibration if we decide to produce some.
A Basic Game Loop
Following the series so far you we have an understanding of the game architecture. Even if just briefly but we know that we need to take input in some form, update the internal state of the game and finally render it to the screen and also produce some sounds and/or vibrations. Now, we are going to discuss and implement the basic game loop.
We handle input, update the state of our internal objects and render the current state. The Update and Render are grouped logically. They are tied together and tend to be executed one after the other.
Anything in Android happens inside an Activity. The Activity will create a View. The View is where everything happens. It is where the touch takes place and the resulting image gets displayed. Think of the Activity as a table that holds a sheet of paper (the View) enabling us to draw something. We will use our pencil to draw something onto the paper. That will be our touch and the actual chemistry happens on the paper so the result of our interaction with the View produces an image. The same is with Activity and View. Something like the following diagram:
The game loop is the heartbeat of every game. We used a very rudimentary one so far without any control over how fast or slow we update our game state and which frames to render.
To recapitulate, the most rudimentary game loop is a while loop that keeps executing some instructions until we signal it to finish, usually by setting a variable called running to false
The above code runs blindly without a care for timing and resources. If you have a fast device then it will run very fast and if you have a slow one it will run slower.
The updateGameState() updates the state of every object in the game and the displayGameState() renders the objects into an image which is displayed onto the screen.
There are two things we should consider here: FPS and UPS.
FPS – Frames per Second – the number of times displayGameState() is being called per second.
UPS – Update per Second – the number of times updateGameState() is being called per second.
Ideally the update and render methods will be called the same number of times per second (preferably not less than 20-25 times per second). 25 FPS is usually enough on a phone so us humans won’t notice the animation being sluggish.
For example if we target 25 FPS then it means we have to call the displayGameState() method every 40ms (1000 / 25 = 40ms, 1000ms = 1s). We need to bear in mind that updateGameState() is also called before the display method and for us to reach 25 FPS, we have to make sure that the update – display sequence executes in exactly 40ms. If it takes less than 40ms, then we have a higher FPS. If it takes more than that, then we have a slower running game.
Let’s see some examples to understand the FPS better.
The following diagram shows exactly 1 FPS. It takes the update – render cycle exactly one second to execute. This means that you will see the image on the screen change once every second.
1 Frame per Second
The following diagram shows 10FPS. An update – render cycle takes 100ms. This means every tenth of a second the image changes.
10 FPS
But the above scenario means that the update-render cycle executes in 1/10 of a second EVERY time. That is an assumption and we can’t control the actual times on cycle executes, or can we? What happens if we have 200 enemies and every enemy is shooting at us? We need to update the state of each enemy and the states of their bullets and check for collisions in one single update. It’s different when we have just 2 enemies. The times will clearly differ. The same applies to the render method. Rendering 200 firing droids will clearly take more time than rendering only 2.
So what are the scenarios? We could have an update-render cycle that finishes in less than 100ms (1/10 of a second), finishes in exactly 100ms or finishes in more than that. On a powerful hardware it will be faster than on a weaker one. Let’s see the diagrams.
The cycle finishes before the desired timeframe so we have a small amount of free time before running the next cycle.
Frame with time to spare
The following diagram shows a cycle which falls behind. That means that the time it takes for a update-render cycle to finish is greater than the desired one. If it takes 12ms that means we are 2ms behind (still considering the 10FPS). This can mount up and every cycle we loose time and the game will run slowly.
Overdue Frame
The first situation is the desired one. This gives us some free time to do something before we kick off the next cycle. We don’t need to do anything so we just tell the game loop to go to sleep for the remaining time period and wake up when the next cycle is due. If we won’t do this the game will run quicker than intended. By introducing the sleep time we achieved constant frame rate.
The second situation (I skipped the ideal one as it almost never happens) when the loop is behind, requires a different approach.
To achieve constant speed in a game we need to update the state of our objects when required. Imagine a droid approaching you at a constant speed. You know if it travelled half the screen in one second, so it will take another second to reach the other side of the screen. To calculate the position accurately we need to know either the time delta since the last postion, and the current speed of the droid, or we update the position (status) of the droid at constant intervals. I will choose the second one as playing with deltas in the game update can be tricky. To achieve a constant game speed we will have to skip displaying frames. Game speed is NOT FPS!
Examine the following diagram. It is a scenario in which the update-render cycle takes longer than the desired time so we have to catch up. To do that we will skip the rendering of this frame and will do another update so the game speed won’t be affected. We’ll do a normal cycle in the next frame with even some time to give to the CPU to rest.
Constant Game Speed with Variable FPS
The above scenario has many variations. You can imagine the game update taking more than one full frame. In this case we can do nothing to keep the game speed constant and the game will run slower. We might have to skip multiple renderings to keep the speed consta