How to develop Pong for Android

Note: This guide was written a little while back, and it looks like there have been some changes since (specifically it looks like a setting in eclipse) see comments for details if you have any problems

So it turns out I’m going to be having an article published in this months’ print issue of the video-game industry magazine “Develop”. Quite how that happened I have no idea, but I’m totally thrilled about it and so wanted to do something game-related in case any of that magazine’s readers decide to check out the blog afterwards. (EDIT: Unfortunately the article never materialized, I had to find this out by buying the magazine and then realizing that I wasn’t in it. haven’t heard a peep out of them either. nice!)

I do, however, need to make one thing really, really clear first of all…

I AM NOT A GAME DEVELOPER!

I don’t purport to be one, I don’t even particularly want to be one. I don’t really know the first thing about making a decent game engine, although that’s not to say I haven’t dabbled in the past. One thing that you should therefore bear in mind is that what follows is likely to be a textbook example of how not to code games. What it will do though, hopefully, is to demonstrate enough about the Android platform such that anyone who IS a game developer would be able to work through this example and figure out how to do it “the good way”.

I have also cut a lot of corners here in terms of general good programming practices. Within the example you’ll find tons of hard coded literals within methods. I have only done this here because I’m attempting to strip down the code to the very basics to help you see what’s going on.

My twin brother Stew, a game developer by trade, once told me that whenever he’s trying to get to grips with a new API the first thing he does is knock out a Bejeweled clone in all its recursive and particle-laden glory. Personally, I tend to go for pong 🙂

So here we go then: Let’s make Pong for the Android platform!

 


 

Start up a new Project

I went for the following options when starting up this project; Feel free to substitute in your own alternatives if you want, but bear in mind that if you do then you’ll need to alter the rest of the code to accommodate.

 


 

The basic architecture we’re going for

We are going to be aiming for only one Activity. This activity will be “playing pong”, and this will be the only activity that a user will be able to do with our application. Other potential activities could have been “looking at the high score table” or “selecting options from the menu”, but those won’t be implemented here. Moreover, we are actually not going to change the Activity at all from the one you’re given when you start the project, because all of the work is going to be done by a View.

We are going to create a new type of view; one which has a thread associated with it. The job of this view will be to start and stop the thread, and to listen for user interaction.

The thread will also be a new type of thread, one which has a game state associated with it. The role of this thread will be to run two methods over and over: update() and draw(), both of which will be methods within the aforementioned state. The thread will also create Canvas and Paint objects (which are used for drawing).
The game state object will be a set of methods and members defining what the current state of the game is.

 


 

Implementing the GameView

So as previously mentioned, there should be no need for us to change the default activity that you’re given when you create a new project, but just in case, open up the file and make sure that all it’s doing is defining the content view as being your layout.xml file. It should just look something like this;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

We are actually going to be creating a new type of view called a GameView, and then just putting a reference to it in our layout xml, meaning that the above will be fine just as it is. Create a new java source file called “GameView.java” in your src directory, and add in the following code;

public class GameView extends SurfaceView  implements SurfaceHolder.Callback
 {
    private GameThread _thread;

    public GameView(Context context, AttributeSet attrs) {
        super(context, attrs);

    	//So we can listen for events...
        SurfaceHolder holder = getHolder();
        holder.addCallback(this);
        setFocusable(true); 

        //and instantiate the thread
        _thread = new GameThread(holder, context, new Handler());
    }  

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent msg) {
        return _thread.getGameState().keyPressed(keyCode, msg);
    }

    //Implemented as part of the SurfaceHolder.Callback interface
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		//Mandatory, just swallowing it for this example

	}

    //Implemented as part of the SurfaceHolder.Callback interface
	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		_thread.start();
	}

    //Implemented as part of the SurfaceHolder.Callback interface
	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
        _thread.stop();
	}
}

This code will give you errors when you first paste it, because you have not yet implemented the “GameThread” object that exists here as a member. Ignore the errors for now and resist running until we’re done! Let’s just do a quick post-mortem of the above code. It’s a new type of View that extends the android “SurfaceView” object. This is a special kind of view that provides a dedicated drawing surface. As we are interested in hearing about any alterations and interactions pertaining to the view, we therefore also implement the “Callback” interface nested within the SurfaceView class, which means we need the three methods “surfaceCreated”, “surfaceChanged” and “surfaceDestroyed”. I start and stop the thread within the create/destroy methods, and just swallow the “changed” one.

You will also notice the “onKeyDown” method, which is overridden from a method that exists in every View (it’s in the View object, in fact). We don’t want our view to be making changes directly to our game state, the game state should change itself based on the user interaction. Therefore, all we do if a key is pressed is pass the information down to the game state (which, again, you haven’t implemented yet).

The final thing to do is to head into your layout.xml file and add in a reference to your new view. Just replace whatever is there with the following code;

<?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.mikey.pong.GameView
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>

Obviously changing the package name to whatever you called yours. The other thing it’s worth pointing out here is that your new View is totally encapsulated: It’s doing it’s own thing on its own thread and will be quite happy sitting alongside other types of view such as spinners and galleries. You could, for example, put in a TextView here to hold the current score and just define that here in your XML rather than pasting text to the screen inside your GameView class. Keeping views seperated, and ensuring that they each have their own job to do and that they stick to doing just that, is a big step towards tidy and modular code.

 


 

Implementing the GameThread

Create another java source file named “GameThread.java” and paste in the following code;

public class GameThread extends Thread {

/** Handle to the surface manager object we interact with */
private SurfaceHolder _surfaceHolder;
private Paint _paint;
private GameState _state;

public GameThread(SurfaceHolder surfaceHolder, Context context, Handler handler)
{
_surfaceHolder = surfaceHolder;
_paint = new Paint();
_state = new GameState();
}

@Override
public void run() {
while(true)
{
Canvas canvas = _surfaceHolder.lockCanvas();
_state.update();
_state.draw(canvas,_paint);
_surfaceHolder.unlockCanvasAndPost(canvas);
}
}

public GameState getGameState()
{
return _state;
}
}

This will just be the thread that runs over and over while the game is running, and extends the “Thread” object (we will override the “run” method from this parent). We also add three members, all of which need to be accessed from the “run” method of the thread. Then there’s the “run” method itself, a continuous loop that just runs the draw and update methods of the game state (which we haven’t implemented yet). Finally there is just a getter method to return the state. We used this in our GameView class, so that we could tell the game state that a key had been pressed.

 


 

Implementing the GameState

This is where I get my head bitten off by any game developers! The horrific basilisk that follows is my very naive implementation of the game “pong”. I’m not going to go in depth into each and every line here, because it should be pretty obvious what it all does. It’s just three methods: draw, update and keypressed. Draw and update each get called in turn by the thread, keypressed gets called whenever a key is pressed. Keypressed and update serve to alter the member variables accordingly, and draw uses these members to draw appropriate shapes.

Create a new Java source file called “GameState.java” and paste in the following code.

public class GameState {

//screen width and height
final int _screenWidth = 300;
final int _screenHeight = 420;

//The ball
final int _ballSize = 10;
int _ballX = 100; 	int _ballY = 100;
int _ballVelocityX = 3; 	int _ballVelocityY = 3;

//The bats
final int _batLength = 75;	final int _batHeight = 10;
int _topBatX = (_screenWidth/2) - (_batLength / 2);
final int _topBatY = 20;
int _bottomBatX = (_screenWidth/2) - (_batLength / 2);	
final int _bottomBatY = 400;
final int _batSpeed = 3;

public GameState()
{
}

//The update method
public void update() {

_ballX += _ballVelocityX;
_ballY += _ballVelocityY;

//DEATH!
if(_ballY > _screenHeight || _ballY < 0)     	
{_ballX = 100; 	_ballY = 100;}  	//Collisions with the sides

if(_ballX > _screenWidth || _ballX < 0)
     		_ballVelocityX *= -1; 	//Collisions with the bats     	

if(_ballX > _topBatX && _ballX < _topBatX+_batLength && _ballY < _topBatY)     	
                 _ballVelocityY *= -1;  //Collisions with the bats     	

if(_ballX > _bottomBatX && _ballX < _bottomBatX+_batLength 
                && _ballY > _bottomBatY)
                       _ballVelocityY *= -1;
}

public boolean keyPressed(int keyCode, KeyEvent msg)
{
if(keyCode == KeyEvent.KEYCODE_DPAD_LEFT) //left
{
_topBatX += _batSpeed; _bottomBatX -= _batSpeed;
}

if(keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) //right
{
_topBatX -= _batSpeed; _bottomBatX += _batSpeed;
}

return true;
}

//the draw method
public void draw(Canvas canvas, Paint paint) {

//Clear the screen
canvas.drawRGB(20, 20, 20);

//set the colour
paint.setARGB(200, 0, 200, 0);

//draw the ball
canvas.drawRect(new Rect(_ballX,_ballY,_ballX + _ballSize,_ballY + _ballSize),
                             paint);

//draw the bats
canvas.drawRect(new Rect(_topBatX, _topBatY, _topBatX + _batLength,
                                      _topBatY + _batHeight), paint); //top bat
canvas.drawRect(new Rect(_bottomBatX, _bottomBatY, _bottomBatX + _batLength, 
                                      _bottomBatY + _batHeight), paint); //bottom bat

}
}

the two objects used in the “draw” method, paint and canvas, both contain extensive methods with which to draw and paste things to the screen. I won’t go into all the details here, but check out the API’s for both if you want more information, they’re both in the Graphics package.


And that is it!

Okay: You should now have all the code you need in order to run this thing. If you have any more errors, make sure you’ve optimized your imports on each of the four source files (just open each one and press ctrl-shift-O to have Eclipse do this for you). Run the game and you should see a ball bouncing around and two bats, pushing the left and right buttons on the android emulator should move the bats.

So concludes the horrific foray of a non-game developer into the world of Android games development. This will very much be a one off for me, as I’m more interested in e-commerce and the web, but this has been fun anyway and I can think of worse ways to spend a Saturday morning! I don’t think I’ve ever been more in need of a bacon sarnie than I am now.

Cheers!

41 thoughts on “How to develop Pong for Android

  1. Hey, first of all, thanks for the tutorial. I’ve been looking for something that starts from scratch like this.

    Unfortunately, I cannot get this tutorial working. I tried simply pasting the code in from this site and ctr+shift+O on every file. It crashes when the virtual device tries to open it.

    Any ideas? I have the virtual device set to Android 2.2

    Thanks.

      • I must have done some imports wrong, I now have it working.

        I am new to Android developing, but I was trying to implement touch into this tutorial (so you can move by touch instead of trackball),

        Is this simple to do?

        Thanks for the tutorial! It was great

  2. HI
    I copied the code.
    Every thing is fine but on emulator screen i can see only message
    Hello World Pong.

    HOw to play game

    • Thanks for this Mikey 🙂

      Btw, 2 errors/warnings can pop up that you may want to warn people about.

      1) Import the android libraries, because it caused me endless shutdowns as I had imported the java library for the Handler class.
      2) It’ll complain about the minSdkVersion (2) being lower than 2.2’s Api (8), but this causes no problems.

  3. This was excellent. I was struggling with drawing primitive shapes and then having them animate like this. I started butchering the code to make an AI driven top paddle and a touch driven bottom paddle. Someone was looking for touch, so here’s what I did:

    /*
    * Implemented in GameState.java, needs an import of android.view.MotionEvent
    *
    * If screen is touched, make bottom paddle center paddle on X coordinate
    */
    public boolean motionDetected(MotionEvent event) {
    float x = event.getX();
    _bottomPaddleX = (int)x – (_paddleLength/2);
    return true;
    }

    /*
    * Implemented in GameView.java, needs an import of android.view.MotionEvent
    *
    * calls getGameState().motionDetected() if there’s a touch on the screen.
    */
    public boolean onTouchEvent(MotionEvent event) {
    return _thread.getGameState().motionDetected(event);
    }

    REMEMBER: I altered the code to only move the bottom paddle.

  4. Wanted to point out a few issues I ran across with this tutorial. First I am 100% new to anything java and had very very limited experience with python, After several days of playing around with other tutorials I returned to this one in hopes to get it working after many failed attempts. I am not sure if I made the errors happen or if it is the newest versions of eclipse and android sdk. First the main.xml if you copy and paste the above code will have nothing but errors and will not run. Being a total noob it was discouraging to say the least as I had no knowledge of how to fix this. But after learning how the xml functioned and how eclipse allowed me to edit things i was able to fix the issues “sort of” . I basically pasted the above code, went to the graphic tab and forced some changes to the code and ended up with this code “it isn’t correct but is working as of now”

    That code above will get the game working and allow a new person to programming to see what is going on via the graphical tab in the xml area

    also Tim posted up some touch controls, thanks for that help, but if you try to copy and paste or type the above mentioned code it is broken based on the defining names, you have paddle in place of bat. _bottompaddle vs _bottomBat. Here is what my changes look like for the touch controls.
    /*
    * Implemented in GameState.java, needs an import of android.view.MotionEvent
    *
    * If screen is touched, make bottom paddle center paddle on X coordinate
    */
    public boolean motionDetected(MotionEvent event) {
    float x = event.getX();
    _bottomBatX = (int)x -(_batLength/2);
    return true;
    }

    Tim stated he was working on the AI part, I would love to see the code for that if you ever finished it Tim.

    • I would highly recommend going through the Basic Orientation at developers.android.com before attempting this tutorial, especially if you have little to no experience with Java and/or Android. The issues you’re having are very basic and easily understood after going through the basic orientation (shouldn’t take longer than an hour.)

  5. I keep getting this error… Also I dont see layout.xml, just main.xml and androidmanifest.xml [2011-11-29 17:47:30 – Pong] AndroidManifest.xml does not declare a Java package: Build aborted.

    I am using Android 2.33 and newest eclipse. Should I try and earlier version of android or am I doing somehting wrong?

  6. I really like this tutorial you did a good job, but however i have a question?

    is it possible to upgrade the framerate? i’d like to call the draw function like 25times a second?

    perhaps someone could help me out? i want to make my game run smoother.

    • Hey bud. To be honest, I don’t really do much android stuff any more and have never really been a games programmer, this tute was really only supposed to be a nudge. You might want to try looking over some of the google example code (such as the lunar lander example) for more efficient ways to push pixels around.

  7. i dont have a layou.xml file when i start a new app. i have a main.xml file in a “layout” folder. so this instruction is confusing:

    The final thing to do is to head into your layout.xml file and add in a reference to your new view. Just replace whatever is there with the following code.

    should i create a layout.xml file too and have it and the main.xml file in the layout folder? should i just put the code in the main.xml file and not have a layout.xml file?

  8. i got it to work, although i did have to add several imports such as these:

    import android.content.Context;
    import android.os.Handler;
    import android.util.AttributeSet;
    import android.view.KeyEvent;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;

    to the various files, but fortunately eclipse recomended these additions when i put my curser on each of the red ‘x’s.

    also the “layout.xml file” code i copied to the “main.xml” file of my “layout” folder. the slow speed reminded me of when i did a java pool game 10 or 15 years ago. when you did the “break” of 15 pool balls it slowed a bit.

  9. @Override
    public boolean onTouchEvent(MotionEvent event) {
    float x = event.getX();
    float y = event.getY();
    gameThread.getGameState().surfaceTouched(x, y);
    return super.onTouchEvent(event);
    }

    public boolean surfaceTouched(float posX, float posY) {
    _topBatX = (int) posX;
    _bottomBatX = (int) posX;

    return true;
    }

  10. The previous comment made it available for you to add touch capability to the game, but wasn’t complete. Here’s the complete one.

    In “GameView.java” add:

    private float _x = 0;
    private float _y = 0;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
    _x = event.getX();
    _y = event.getY();
    }
    if (event.getAction() == MotionEvent.ACTION_MOVE) {
    final float xdiff = (_x – event.getX());
    final float ydiff = (_y – event.getY());
    _thread.getGameState().surfaceTouched(_x, _y);

    _x = event.getX();
    _y = event.getY();
    }
    return true;
    }

    Then in “GameState.java” add:

    public boolean surfaceTouched(float posX, float posY) {
    _topBatX = (int) posX;
    _bottomBatX = (int) posX;

    return true;
    }

  11. Thanks for the tutorial!

    I have no experience with developing for Android (I’ve just gone through Basic Orientation at developers.android.com), but I am familiar with Java. I found this tutorial to be a perfect transition to Android for someone who has developed VERY basic games in Java.

  12. Im still learning the basics but i got rid of all the errors i had except i get an error on the xml i get an error on the match_parent and when i put my mouse over it it says string types not allowed. Help!

  13. Im still newbie in java programming ….
    This’s really help
    thanx
    I’m wondering, how to change the ball and the bat into a graphic that will used as a ball and a bat instead just that rectangle ?

  14. Hi I’m getting this errors could you tell me what’s going on, in Netbeans, not Eclipse:

    Compiling 6 source files to /Users/pedroalonso/NetBeansProjects/TestApp/bin/classes
    /Users/pedroalonso/NetBeansProjects/TestApp/src/My/Test/GameThread.java:24: cannot find symbol
    symbol : class Context
    location: class My.Test.GameThread
    public GameThread(SurfaceHolder surfaceHolder, Context context, Handler handler)
    /Users/pedroalonso/NetBeansProjects/TestApp/src/My/Test/GameThread.java:24: cannot find symbol
    symbol : class Handler
    location: class My.Test.GameThread
    public GameThread(SurfaceHolder surfaceHolder, Context context, Handler handler)
    /Users/pedroalonso/NetBeansProjects/TestApp/src/My/Test/GameView.java:22: cannot find symbol
    symbol : class Context
    location: class My.Test.GameView
    public GameView(Context context, AttributeSet attrs) {
    /Users/pedroalonso/NetBeansProjects/TestApp/src/My/Test/GameView.java:22: cannot find symbol
    symbol : class AttributeSet
    location: class My.Test.GameView
    public GameView(Context context, AttributeSet attrs) {
    /Users/pedroalonso/NetBeansProjects/TestApp/src/My/Test/GameState.java:86: cannot find symbol
    symbol : class Rect
    location: class My.Test.GameState
    canvas.drawRect(new Rect(_ballX,_ballY,_ballX + _ballSize,_ballY + _ballSize),
    /Users/pedroalonso/NetBeansProjects/TestApp/src/My/Test/GameState.java:90: cannot find symbol
    symbol : class Rect
    location: class My.Test.GameState
    canvas.drawRect(new Rect(_topBatX, _topBatY, _topBatX + _batLength,
    /Users/pedroalonso/NetBeansProjects/TestApp/src/My/Test/GameState.java:92: cannot find symbol
    symbol : class Rect
    location: class My.Test.GameState
    canvas.drawRect(new Rect(_bottomBatX, _bottomBatY, _bottomBatX + _batLength,
    /Users/pedroalonso/NetBeansProjects/TestApp/src/My/Test/GameView.java:31: cannot find symbol
    symbol : class Handler
    location: class My.Test.GameView
    _thread = new GameThread(holder, context, new Handler());
    Note: /Users/pedroalonso/NetBeansProjects/TestApp/src/My/Test/GameView.java uses or overrides a deprecated API.
    Note: Recompile with -Xlint:deprecation for details.
    8 errors

Leave a reply to Pedro Cancel reply