Android Game Loops

The Following article is copied from dewitters-gameloop and as this is a very informative article, and due to the transient nature of the internet, made a copy to maintain the articles availability. If you wish to add to this article or make changes, let me know.


The game loop is the heartbeat of every game, no game can run without it. But unfortunately for every new game programmer, there aren’t any good articles on the internet who provide the proper information on this topic. But fear not, because you have just stumbled upon the one and only article that gives the game loop the attention it deserves. Thanks to my job as a game programmer, I come into contact with a lot of code for small mobile games. And it always amazes me how many game loop implementations are out there. You might wonder yourself how a simple thing like that can be written in different ways. Well, it can, and I will discuss the pros and cons of the most popular implementations, and give you the (in my opinion) best solution of implementing a game loop.

The Game Loop

Every game consists of a sequence of getting user input, updating the game state, handling AI, playing music and sound effects, and displaying the game. This sequence is handled through the game loop. Just like I said in the introduction, the game loop is the heartbeat of every game. In this article I will not go into details on any of the above mentioned tasks, but will concentrate on the game loop alone. That’s also why I simplified the tasks to only 2 functions: updating the game and displaying it. Here is some example code of the game loop in it’s most simplest form:

    bool game_is_running = true;

    while( game_is_running ) {
        update_game();
        display_game();
    }

The problem with this simple loop is that it doesn’t handle time, the game just runs. On slower hardware the game runs slower, and on faster hardware faster. Back in the old days when the speed of the hardware was known, this wasn’t a problem, but nowadays there are so many hardware platforms out there, that we have to implement some sort of time handling. There are many ways to do this, and I’ll discuss them in the following sections. First, let me explain 2 terms that are used throughout this article:

FPS
FPS is an abbreviation for Frames Per Second. In the context of the above implementation, it is the number of times display_game() is called per second.
Game Speed
Game Speed is the number of times the game state gets updated per second, or in other words, the number of times update_game() is called per second.

FPS dependent on Constant Game Speed

Implementation

An easy solution to the timing issue is to just let the game run on a steady 25 frames per second. The code then looks like this:

    const int FRAMES_PER_SECOND = 25;
    const int SKIP_TICKS = 1000 / FRAMES_PER_SECOND;

    DWORD next_game_tick = GetTickCount();
    // GetTickCount() returns the current number of milliseconds
    // that have elapsed since the system was started

    int sleep_time = 0;

    bool game_is_running = true;

    while( game_is_running ) {
        update_game();
        display_game();

        next_game_tick += SKIP_TICKS;
        sleep_time = next_game_tick - GetTickCount();
        if( sleep_time >= 0 ) {
            Sleep( sleep_time );
        }
        else {
            // Shit, we are running behind!
        }
    }
This is a solution with one huge benefit: it’s simple! Since you know that update_game() gets called 25 times per second, writing your game code is quite straight forward. For example, implementing a replay function in this kind of game loop is easy. If no random values are used in the game, you can just log the input changes of the user and replay them later. On your testing hardware you can adapt the FRAMES_PER_SECOND to an ideal value, but what will happen on faster or slower hardware? Well, let’s find out.

Slow hardware

If the hardware can handle the defined FPS, no problem. But the problems will start when the hardware can’t handle it. The game will run slower. In the worst case the game has some heavy chunks where the game will run really slow, and some chunks where it runs normal. The timing becomes variable which can make your game unplayable.

Fast hardware

The game will have no problems on fast hardware, but you are wasting so many precious clock cycles. Running a game on 25 or 30 FPS when it could easily do 300 FPS… shame on you! You will lose a lot of visual appeal with this, especially with fast moving objects. On the other hand, with mobile devices, this can be seen as a benefit. Not letting the game constantly run at it’s edge could save some battery time.

Conclusion

Making the FPS dependent on a constant game speed is a solution that is quickly implemented and keeps the game code simple. But there are some problems: Defining a high FPS will pose problems on slower hardware, and defining a low FPS will waste visual appeal on fast hardware.

Game Speed dependent on Variable FPS

Implementation

Another implementation of a game loop is to let it run as fast as possible, and let the FPS dictate the game speed. The game is updated with the time difference of the previous frame.

DWORD prev_frame_tick; DWORD curr_frame_tick = GetTickCount(); bool game_is_running = true; while( game_is_running ) { prev_frame_tick = curr_frame_tick; curr_frame_tick = GetTickCount(); update_game( curr_frame_tick - prev_frame_tick ); display_game(); }

The game code becomes a bit more complicated because we now have to consider the time difference in the update_game() function. But still, it’s not that hard. At first sight this looks like the ideal solution to our problem. I have seen many smart programmers implement this kind of game loop. Some of them probably wished they would have read this article before they implemented their loop. I will show you in a minute that this loop can have serious problems on both slow and fast (yes, FAST!) hardware.

Slow Hardware

Slow hardware can sometimes cause certain delays at some points, where the game gets “heavy”. This can definitely occur with a 3D game, where at a certain time too many polygons get shown. This drop in frame rate will affect the input response time, and therefore also the player’s reaction time. The updating of the game will also feel the delay and the game state will be updated in big time-chunks. As a result the reaction time of the player, and also that of the AI, will slow down and can make a simple maneuver fail, or even impossible. For example, an obstacle that could be avoided with a normal FPS, can become impossible to avoid with a slow FPS. A more serious problem with slow hardware is that when using physics, your simulation can even explode

!

Fast Hardware

You are probably wondering how the above game loop can go wrong on fast hardware. Unfortunately, it can, and to show you, let me first explain something about math on a computer. The memory space of a float or double value is limited, so some values cannot be represented. For example, 0.1 cannot be represented binary, and therefore is rounded when stored in a double. Let me show you using python:

>>> 0.1
0.10000000000000001

This itself is not dramatic, but the consequences are. Let’s say you have a race-car that has a speed of 0.001 units per millisecond. After 10 seconds your race-car will have traveled a distance of 10.0. If you split this calculation up like a game would do, you have the following function using frames per second as input:

>>> def get_distance( fps ): ... skip_ticks = 1000 / fps ... total_ticks = 0 ... distance = 0.0 ... speed_per_tick = 0.001 ... while total_ticks < 10000: ... distance += speed_per_tick * skip_ticks ... total_ticks += skip_ticks ... return distance

Now we can calculate the distance at 40 frames per second:

>>> get_distance( 40 )
10.000000000000075

Wait a minute… this is not 10.0??? What happened? Well, because we split up the calculation in 400 additions, a rounding error got big. I wonder what will happen at 100 frames per second…

>>> get_distance( 100 )
9.9999999999998312

What??? The error is even bigger!! Well, because we have more additions at 100 fps, the rounding error has more chance to get big. So the game will differ when running at 40 or 100 frames per second:

>>> get_distance( 40 ) - get_distance( 100 )
2.4336088699783431e-13

You might think that this difference is too small to be seen in the game itself. But the real problem will start when you use this incorrect value to do some more calculations. This way a small error can become big, and fuck up your game at high frame rates. Chances of that happening? Big enough to consider it! I have seen a game that used this kind of game loop, and which indeed gave trouble at high frame rates. After the programmer found out that the problem was hiding in the core of the game, only a lot of code rewriting could fix it.

Conclusion

This kind of game loop may seem very good at first sight, but don’t be fooled. Both slow and fast hardware can cause serious problems for your game. And besides, the implementation of the game update function is harder than when you use a fixed frame rate, so why use it?

Constant Game Speed with Maximum FPS

Implementation

Our first solution, FPS dependent on Constant Game Speed, has a problem when running on slow hardware. Both the game speed and the framerate will drop in that case. A possible solution for this could be to keep updating the game at that rate, but reduce the rendering framerate. This can be done using following game loop:

const int TICKS_PER_SECOND = 50; const int SKIP_TICKS = 1000 / TICKS_PER_SECOND; const int MAX_FRAMESKIP = 10; DWORD next_game_tick = GetTickCount(); int loops; bool game_is_running = true; while( game_is_running ) { loops = 0; while( GetTickCount() > next_game_tick && loops < MAX_FRAMESKIP) { update_game(); next_game_tick += SKIP_TICKS; loops++; } display_game(); }

The game will be updated at a steady 50 times per second, and rendering is done as fast as possible. Remark that when rendering is done more than 50 times per second, some subsequent frames will be the same, so actual visual frames will be dispayed at a maximum of 50 frames per second. When running on slow hardware, the framerate can drop until the game update loop will reach MAX_FRAMESKIP. In practice this means that when our render FPS drops below 5 (= FRAMES_PER_SECOND / MAX_FRAMESKIP), the actual game will slow down.

Slow hardware

On slow hardware the frames per second will drop, but the game itself will hopefully run at the normal speed. If the hardware still can’t handle this, the game itself will run slower and the framerate will not be smooth at all.

Fast hardware

The game will have no problems on fast hardware, but like the first solution, you are wasting so many precious clock cycles that can be used for a higher framerate. Finding the balance between a fast update rate and being able to run on slow hardware is crucial.

Conclusion

Using a constant game speed with a maximum FPS is a solution that is easy to implement and keeps the game code simple. But there are still some problems: Defining a high FPS can still pose problems on slow hardware (but not as severe as the first solution), and defining a low FPS will waste visual appeal on fast hardware.

Constant Game Speed independent of Variable FPS

Implementation

Would it be possible to improve the above solution even further to run faster on slow hardware, and be visually more atractive on faster hardware? Well, lucky for us, this is possible. The game state itself doesn’t need to be updated 60 times per second. Player input, AI and the updating of the game state have enough with 25 frames per second. So let’s try to call the update_game() 25 times per second, no more, no less. The rendering, on the other hand, needs to be as fast as the hardware can handle. But a slow frame rate shouldn’t interfere with the updating of the game. The way to achieve this is by using the following game loop:

const int TICKS_PER_SECOND = 25; const int SKIP_TICKS = 1000 / TICKS_PER_SECOND; const int MAX_FRAMESKIP = 5; DWORD next_game_tick = GetTickCount(); int loops; float interpolation; bool game_is_running = true; while( game_is_running ) { loops = 0; while( GetTickCount() > next_game_tick && loops < MAX_FRAMESKIP) { update_game(); next_game_tick += SKIP_TICKS; loops++; } interpolation = float( GetTickCount() + SKIP_TICKS - next_game_tick ) / float( SKIP_TICKS ); display_game( interpolation ); }

With this kind of game loop, the implementation of update_game() will stay easy. But unfortunately, the display_game() function gets more complex. You will have to implement a prediction function that takes the interpolation as argument. But don’t worry, this isn’t hard, it just takes a bit more work. I’ll explain below how this interpolation and prediction works, but first let me show you why it is needed.

The Need for Interpolation

The gamestate gets updated 25 times per second, so if you don’t use interpolation in your rendering, frames will also be displayed at this speed. Remark that 25 fps isn’t as slow as some people think, movies for example run at 24 frames per second. So 25 fps should be enough for a visually pleasing experience, but for fast moving objects, we can still see a improvement when doing more FPS. So what we can do is make fast movements more smooth in between the frames. And this is where interpolation and a prediction function can provide a solution.

Interpolation and Prediction

Like I said the game code runs on it’s own frames per second, so when you draw/render your frames, it is possible that it’s in between 2 gameticks. Let’s say you have just updated your gamestate for the 10Th time, and now you are going to render the scene. This render will be in between the 10Th and 11Th game update. So it is possible that the render is at about 10.3. The ‘interpolation’ value then holds 0.3. Take this example: I have a car that moves every game tick like this:

    position = position + speed;

If in the 10Th gametick the position is 500, and the speed is 100, then in the 11Th gametick the position will be 600. So where will you place your car when you render it? You could just take the position of the last gametick (in this case 500). But a better way is to predict where the car would be at exact 10.3, and this happens like this:

    view_position = position + (speed * interpolation)

The car will then be rendered at position 530. So basically the interpolation variable contains the value that is in between the previous gametick and the next one (previous = 0.0, next = 1.0). What you have to do then is make a “prediction” function where the car/camera/… would be placed at the render time. You can base this prediction function on the speed of the object, steering or rotation speed. It doesn’t need to be complicated because we only use it to smooth things out in between the frames. It is indeed possible that an object gets rendered into another object right before a collision gets detected. But like we have seen before, the game is updated 25 frames per second, and so when this happens, the error is only shown for a fraction of a second, hardly noticeable to the human eye.

Slow Hardware

In most cases, update_game() will take far less time than display_game(). In fact, we can assume that even on slow hardware the update_game() function can run 25 times per second. So our game will handle player input and update the game state without much trouble, even if the game will only display 15 frames per second.

Fast Hardware

On fast hardware, the game will still run at a constant pace of 25 times per second, but the updating of the screen will be way faster than this. The interpolation/prediction method will create the visual appeal that the game is actually running at a high frame rate. The good thing is that you kind of cheat with your FPS. Because you don’t update your game state every frame, only the visualization, your game will have a higher FPS than with the second method I described.

Conclusion

Making the game state independent of the FPS seems to be the best implementation for a game loop. However, you will have to implement a prediction function in display_game(), but this isn’t that hard to achieve.

Overall Conclusion

A game loop has more to it than you think. We’ve reviewed 4 possible implementations, and it seems that there is one of them which you should definitely avoid, and that’s the one where a variable FPS dictates the game speed. A constant frame rate can be a good and simple solution for mobile devices, but when you want to get everything the hardware has got, best use a game loop where the FPS is completely independent of the game speed, using a prediction function for high framerates. If you don’t want to bother with a prediction function, you can work with a maximum frame rate, but finding the right game update rate for both slow and fast hardware can be tricky.


Android Method
The game loop is the heartbeat of every game. We used a very rudimentary one so far (you can find it here) 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
boolean running = true; while (!running) { updateGameState(); displayGameState(); }

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.

The following diagram shows 10FPS. An update – render cycle takes 100ms. This means every tenth of a second the image changes.

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.

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.

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.


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 constant but we have to make sure that we set the maximum number of frames allowed to be skipped because it can take quite a few updates to catch up and in case we skipped 15 frames that means we lost a lot from the game and it will just be unplayable.

The MainThread.java‘s run() looks like this:

// desired fps private final static int MAX_FPS = 50; // maximum number of frames to be skipped private final static int MAX_FRAME_SKIPS = 5; // the frame period private final static int FRAME_PERIOD = 1000 / MAX_FPS; @Override public void run() { Canvas canvas; Log.d(TAG, "Starting game loop"); long beginTime; // the time when the cycle begun long timeDiff; // the time it took for the cycle to execute int sleepTime; // ms to sleep (<0 if we're behind) int framesSkipped; // number of frames being skipped sleepTime = 0; while (running) { canvas = null; // try locking the canvas for exclusive pixel editing // in the surface try { canvas = this.surfaceHolder.lockCanvas(); synchronized (surfaceHolder) { beginTime = System.currentTimeMillis(); framesSkipped = 0; // resetting the frames skipped // update game state this.gamePanel.update(); // render state to the screen // draws the canvas on the panel this.gamePanel.render(canvas); // calculate how long did the cycle take timeDiff = System.currentTimeMillis() - beginTime; // calculate sleep time sleepTime = (int)(FRAME_PERIOD - timeDiff); if (sleepTime > 0) { // if sleepTime > 0 we're OK try { // send the thread to sleep for a short period // very useful for battery saving Thread.sleep(sleepTime); } catch (InterruptedException e) {} } while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) { // we need to catch up // update without rendering this.gamePanel.update(); // add frame period to check if in next frame sleepTime += FRAME_PERIOD; framesSkipped++; } } } finally { // in case of an exception the surface is not left in // an inconsistent state if (canvas != null) { surfaceHolder.unlockCanvasAndPost(canvas); } } // end finally } }

Examine the above code very carefully as it implements the logic behind the diagram.
You can find the full code in the downloadable project.

There is another approach which I like. It is constant game speed with maximum number of frames per second. It uses interpolation to draw the state and it occurs on fast hardwares when there is time left for another rendering before the next game update. This can enhance the visuals of a game as it enables smoother animation but because we use mobile devices, giving the CPU some rest will save the battery quite a lot.
There is an awesome article on game loops here. I personally understood the game loops reading this article so I highly recommend it. The best I could find.

Note that I also modified the default values in the Speed.java class. The speed is measured in units/second.
Because we are setting our desired FPS to 50 that means that the speed will increase by 50*speed.value every update. To have the speed of let’s say 40 pixels/second you will need to set the speed delta for every tick to 2 (40 / (1000 / 50) = 2). In other words you need the droid to advance 2 pixels every game update (when you have 50 game updates per second) to cover 40 pixels per second.


How can we measure it? Check the new MainThread.java class.

package net.obviam.droidz; import java.text.DecimalFormat; import android.graphics.Canvas; import android.util.Log; import android.view.SurfaceHolder; /** * @author impaler * * The Main thread which contains the game loop. The thread must have access to * the surface view and holder to trigger events every game tick. */ public class MainThread extends Thread { private static final String TAG = MainThread.class.getSimpleName(); // desired fps private final static int MAX_FPS = 50; // maximum number of frames to be skipped private final static int MAX_FRAME_SKIPS = 5; // the frame period private final static int FRAME_PERIOD = 1000 / MAX_FPS; // Stuff for stats */ private DecimalFormat df = new DecimalFormat("0.##"); // 2 dp // we'll be reading the stats every second private final static int STAT_INTERVAL = 1000; //ms // the average will be calculated by storing // the last n FPSs private final static int FPS_HISTORY_NR = 10; // last time the status was stored private long lastStatusStore = 0; // the status time counter private long statusIntervalTimer = 0l; // number of frames skipped since the game started private long totalFramesSkipped = 0l; // number of frames skipped in a store cycle (1 sec) private long framesSkippedPerStatCycle = 0l; // number of rendered frames in an interval private int frameCountPerStatCycle = 0; private long totalFrameCount = 0l; // the last FPS values private double fpsStore[]; // the number of times the stat has been read private long statsCount = 0; // the average FPS since the game started private double averageFps = 0.0; // Surface holder that can access the physical surface private SurfaceHolder surfaceHolder; // The actual view that handles inputs // and draws to the surface private MainGamePanel gamePanel; // flag to hold game state private boolean running; public void setRunning(boolean running) { this.running = running; } public MainThread(SurfaceHolder surfaceHolder, MainGamePanel gamePanel) { super(); this.surfaceHolder = surfaceHolder; this.gamePanel = gamePanel; } @Override public void run() { Canvas canvas; Log.d(TAG, "Starting game loop"); // initialise timing elements for stat gathering initTimingElements(); long beginTime; // the time when the cycle begun long timeDiff; // the time it took for the cycle to execute int sleepTime; // ms to sleep (<0 if we're behind) int framesSkipped; // number of frames being skipped sleepTime = 0; while (running) { canvas = null; // try locking the canvas for exclusive pixel editing // in the surface try { canvas = this.surfaceHolder.lockCanvas(); synchronized (surfaceHolder) { beginTime = System.currentTimeMillis(); framesSkipped = 0; // resetting the frames skipped // update game state this.gamePanel.update(); // render state to the screen // draws the canvas on the panel this.gamePanel.render(canvas); // calculate how long did the cycle take timeDiff = System.currentTimeMillis() - beginTime; // calculate sleep time sleepTime = (int)(FRAME_PERIOD - timeDiff); if (sleepTime > 0) { // if sleepTime > 0 we're OK try { // send the thread to sleep for a short period // very useful for battery saving Thread.sleep(sleepTime); } catch (InterruptedException e) {} } while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) { // we need to catch up this.gamePanel.update(); // update without rendering sleepTime += FRAME_PERIOD; // add frame period to check if in next frame framesSkipped++; } if (framesSkipped > 0) { Log.d(TAG, "Skipped:" + framesSkipped); } // for statistics framesSkippedPerStatCycle += framesSkipped; // calling the routine to store the gathered statistics storeStats(); } } finally { // in case of an exception the surface is not left in // an inconsistent state if (canvas != null) { surfaceHolder.unlockCanvasAndPost(canvas); } } // end finally } } /** * The statistics - it is called every cycle, it checks if time since last * store is greater than the statistics gathering period (1 sec) and if so * it calculates the FPS for the last period and stores it. * * It tracks the number of frames per period. The number of frames since * the start of the period are summed up and the calculation takes part * only if the next period and the frame count is reset to 0. */ private void storeStats() { frameCountPerStatCycle++; totalFrameCount++; // check the actual time statusIntervalTimer += (System.currentTimeMillis() - statusIntervalTimer); if (statusIntervalTimer >= lastStatusStore + STAT_INTERVAL) { // calculate the actual frames pers status check interval double actualFps = (double)(frameCountPerStatCycle / (STAT_INTERVAL / 1000)); //stores the latest fps in the array fpsStore[(int) statsCount % FPS_HISTORY_NR] = actualFps; // increase the number of times statistics was calculated statsCount++; double totalFps = 0.0; // sum up the stored fps values for (int i = 0; i < FPS_HISTORY_NR; i++) { totalFps += fpsStore[i]; } // obtain the average if (statsCount < FPS_HISTORY_NR) { // in case of the first 10 triggers averageFps = totalFps / statsCount; } else { averageFps = totalFps / FPS_HISTORY_NR; } // saving the number of total frames skipped totalFramesSkipped += framesSkippedPerStatCycle; // resetting the counters after a status record (1 sec) framesSkippedPerStatCycle = 0; statusIntervalTimer = 0; frameCountPerStatCycle = 0; statusIntervalTimer = System.currentTimeMillis(); lastStatusStore = statusIntervalTimer; // Log.d(TAG, "Average FPS:" + df.format(averageFps)); gamePanel.setAvgFps("FPS: " + df.format(averageFps)); } } private void initTimingElements() { // initialise timing elements fpsStore = new double[FPS_HISTORY_NR]; for (int i = 0; i < FPS_HISTORY_NR; i++) { fpsStore[i] = 0.0; } Log.d(TAG + ".initTimingElements()", "Timing elements for stats initialised"); } }

I introduced a simple measuring function. I count the number of frames every second and store them in the fpsStore[] array. The storeStats() is called every tick and if the 1 second interval (STAT_INTERVAL = 1000;) is not reached then it simply adds the number of frames to the existing count.
If the one second is hit then it takes the number of rendered frames and adds them to the array of FPSs. After this I just reset the counters for the current statistics cycle and add the results to a global counter. The average is calculated on the values stored in the last 10 seconds.
Line 171 logs the FPS every second while line 172 sets the avgFps value of the gamePanel instance to be displayed on the screen.

The MainGamePanel.java class’s render method contains the the displayFps call which just draws the text onto the top right corner of the display every time the state is rendered. It also has a private member that is set from the thread.

// the fps to be displayed private String avgFps; public void setAvgFps(String avgFps) { this.avgFps = avgFps; } public void render(Canvas canvas) { canvas.drawColor(Color.BLACK); droid.draw(canvas); // display fps displayFps(canvas, avgFps); } private void displayFps(Canvas canvas, String fps) { if (canvas != null && fps != null) { Paint paint = new Paint(); paint.setARGB(255, 255, 255, 255); canvas.drawText(fps, this.getWidth() - 50, 20, paint); } }
You should have the FPS displayed in the top right corner.



Comments