Android tutorial: How to make a basic game loop and FPS counter
This Android tutorial is all about the basics of Android game development.
You will learn a few things in the tutorial:
- Create a basic game loop
- Display the FPS counter (frames per second) on your canvas
In Android we can paint on a canvas. To make sure we do not lock the screen we need to run the operations in a thread. our basic game consists of 4 important files
- main.xml
- MainActivity
- AnimationView
- AnimationThread
Lets start off simple:
main.xml
The only thing thats in here is our AnimationView! Pretty simple aint it ?
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">Â Â Â Â Â Â
<com.pxr.basegame.AnimationView   Â
android:id="@+id/aview"Â Â Â Â
android:layout_width="match_parent"Â Â Â Â
android:layout_height="match_parent"/>
</FrameLayout>
MainActivity
This is the MainActivity:
package com.pxr.basegame;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
Only thing it does is loading the main.xml. Well... this is so simple
I guess the real fun starts after the break!
AnimationView &Â AnimationThread
This is where the action happens! The AnimationView is the same View that we saw back in main.xml. Inside the AnimationView is an AnimationThread. This thread is responsible for holding our game loop and drawing the FPS counter to the Canvas. I'll just paste it in so you can see it for yourself. ( Code has a lot of comments to make it easier to understand )
package com.pxr.basegame;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
class AnimationView extends SurfaceView implements SurfaceHolder.Callback {
class AnimationThread extends Thread {
/** Are we running ? */
private boolean mRun;
/** Used to figure out elapsed time between frames */
private long mLastTime;
/** Variables for the counter */
private int frameSamplesCollected = 0;
private int frameSampleTime = 0;
private int fps = 0;
/** Handle to the surface manager object we interact with */
private SurfaceHolder mSurfaceHolder;
/** How to display the text */
private Paint textPaint;
public AnimationThread(SurfaceHolder surfaceHolder) {
mSurfaceHolder = surfaceHolder;
/** Initiate the text painter */
textPaint = new Paint();
textPaint.setARGB(255,255,255,255);
textPaint.setTextSize(32);
}
/**
* The actual game loop!
*/
@Override
public void run() {
while (mRun) {
Canvas c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
updatePhysics();
doDraw(c);
}
}finally {
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
/**
* Figures the gamestate based on the passage of
* realtime. Called at the start of draw().
* Only calculates the FPS for now.
*/
private void updatePhysics() {
long now = System.currentTimeMillis();
if (mLastTime != 0) {
//Time difference between now and last time we were here
int time = (int) (now - mLastTime);
frameSampleTime += time;
frameSamplesCollected++;
//After 10 frames
if (frameSamplesCollected == 10) {
//Update the fps variable
fps = (int) (10000 / frameSampleTime);
//Reset the sampletime + frames collected
frameSampleTime = 0;
frameSamplesCollected = 0;
}
}
mLastTime = now;
}
/**
* Draws to the provided Canvas.
*/
private void doDraw(Canvas canvas) {
// Draw the background color. Operations on the Canvas accumulate
// so this is like clearing the screen. In a real game you can
// put in a background image of course
canvas.drawColor(Color.BLACK);
//Draw fps center screen
canvas.drawText(fps + " fps", getWidth() / 2, getHeight() / 2, textPaint);
canvas.restore();
}
/**
* So we can stop/pauze the game loop
*/
public void setRunning(boolean b) {
mRun = b;
}
}
/** The thread that actually draws the animation */
private AnimationThread thread;
public AnimationView(Context context, AttributeSet attrs) {
super(context, attrs);
// register our interest in hearing about changes to our surface
SurfaceHolder holder = getHolder();
holder.addCallback(this);
// create thread only; it's started in surfaceCreated()
thread = new AnimationThread(holder);
}
/**
* Obligatory method that belong to the:implements SurfaceHolder.Callback
*/
/**
* Callback invoked when the surface dimensions change.Â
*/
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
/**
* Callback invoked when the Surface has been created and is ready to be
* used.
*/
public void surfaceCreated(SurfaceHolder holder) {
thread.setRunning(true);
thread.start();
}
/**
* Callback invoked when the Surface has been destroyed and must no longer
* be touched. WARNING: after this method returns, the Surface/Canvas must
* never be touched again!
*/
public void surfaceDestroyed(SurfaceHolder holder) {
// we have to tell thread to shut down & wait for it to finish, or else
// it might touch the Surface after we return and explode
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
}
Well that it. Basic android game development 101
I have uploaded a working Eclipse project so you can play around with it.
Download it here: Eclipse project - basic game loop
Questions ? Leave a comment
Want more ? Subscribe to my RSS feed and stay updated!
No related posts.

March 21st, 2011 - 10:16
Thank you very much for your tutorial and especially including the error-free source code! This was very helpful
March 22nd, 2011 - 01:12
Hi P-xr: Your code runs as advertised. But when I created a new Android project and typed your scripts in, it didn’t work. I am sure that the .java files and main.xml and the manifest are identical in my version, except that I have used different project and class names (and changed the code to match), but it doesn’t work. The debugger says “source not found”. All my paths are set correctly … can you explain what I am doing wrong, or not doing right?
March 22nd, 2011 - 07:11
Mike I think your problem lies in the main.xml. You have to change the following lines
<com.pxr.gamebase.AnimationView
    android:id=”@+id/aview”
    android:layout_width=”match_parent”
    android:layout_height=”match_parent”/>
The first line points to the package. If you copied it from my project you probably have to change it to reflect your own package
I hope that helped a bit.
March 22nd, 2011 - 07:12
Glad it was helpfull
March 22nd, 2011 - 12:33
Hi Mark: I did realise that I needed to edit that line but it had a typo,so that was the problem! Thanks for your help. Now, back to the tutorials …
April 11th, 2011 - 12:34
thanks for your article
i am having this error at my xml side
Multiple annotations found at this line:
- error: Error: String types not allowed (at ‘layout_width’ with value
‘match_parent’).
- error: Error: String types not allowed (at ‘layout_height’ with value
‘match_parent’).
I have exactly the same main.xml as of your(package name is my own).
if you could please help
April 11th, 2011 - 13:27
Have you tried cleaning your project?
May 20th, 2011 - 21:56
Worked like a charm. Plug and play
Thanks!
December 18th, 2011 - 23:50
Hello. I have never programmed before, so im a newbie. Where do i find a program to do this in?
December 20th, 2011 - 13:10
@Dexter Search with reading up on this: http://p-xr.com/android-development-101-preparing-your-environment/
i hope that will get you started!
February 8th, 2012 - 16:30
Hi, thanks for the tutorial is very helpful
could you guide me to create a scoreboard to display a win/lose this game