Introduction

Game development on the Android platform is challenging and rewarding and comes with it's own set of pitfalls and hard learned lessons. In this series of articles I hope to show you some of those pitfalls and maybe teach a lesson or two along the way. While you will be challenged I also hope to help you see the rewards that can come from those challenges.

Background

Mobile Java applications are not a new concept and in fact were one of the original focuses of Sun when it because the java project. There have been mobile java games since the first JVM was put on a mobile device. In the case of the Android things are a little bit different. Android uses what is called the Dalvik Virtual Machine, or DVM, which is an opensource implementation of a JVM. There are several differences between Dalvik and a standard JVM, some subtle, some not so subtle. The DVM is also not aligned to either Java SE or Java ME, but to an apache implementation called Apache Harmony Java. All of this makes for a slight learning curve if you happen to be transitioning from Java ME.

Basic Game Architecture

This example requires three basic classes in order to implement a basic game. The game logic can be extended or changed and the resources can be replaces easily using the same patterns. The file DrawablePanel.java contains the code for DrawablePanel which extends SurfaceView and provides a full screen canvas. The DrawablePanel contains an AnimationThread. This class extends Thread (you could also provide a runnable, whatever pattern is more familiar). The AnimationThread class holds a reference to the DrawablePanel described above and updates the DrawablePanel for game logic and forces a redraw of the panel.

First Steps

I will be using Eclipse as the compilation tool for this tutorial. I am also using the Android Eclipse plugin. Eclipse can be found at
www.eclipse.org/downloads and you can find the ADT plugin at developer.android.com/sdk/eclipse-adt.html

First create an Android project:

Since I will be demonstrating an animated sprite implementation we need a sprite strip. Here is the sprite strip we will be using:

You have to add the asset to the project:

Code

Now we come to the actual coding. First we will create the AnimatedSprite class since that has the least amount of dependencies.

Here we can see that AnimateSprite is a fairly simple class. It basically keeps track of what frame it's currently displaying and increments it during update if the appropriate time has elapsed. If it reaches the end of the list it will wrap around and begin rendering at the start of the list again.

I've abstracted the interaction between the animation logic and display logic with an interface called ISurface. Let's look at that interface now.

ISurface interface

Here we can see that the ISurface interface provides some basic functions. One for initialization which is called at startup or when the sprite is first initialized. The second is the draw function which is pretty self explanatory. The final function is the update function which is what is used by the animation thread to update it's animation(s).

try { c = surfaceHolder.lockCanvas(null); synchronized (surfaceHolder) { panel.onDraw(c); } } finally { // do this in a finally so that if an exception is thrown // during the above, we don't leave the Surface in an // inconsistent state if (c != null) { surfaceHolder.unlockCanvasAndPost(c); } } } }}

This class isn't doing much either, but what it is doing is very important. This class extends Thread. You could also create a runnable and implement threading that way. This way is more obvious which is why I chose it. The run function of this class is where all the work is being done. In this case the function retrieves the current system time and calls it's dependent panel's update function. It then obtains an exclusive lock on the containing surface's canvas and passes that canvas to the surface view's draw function. This call is synchronized to ensure stability.

Now we need to provide a concrete implementation of the ISurface interface for our tutorial. This will be the responsibility of the DrawablePanel class. Let's look at that class now:

This class extends SurfaceView and implements the SurfaceHolder.Callback interface. This is one technique to create a custom view. This class also implements our ISurface interface. It also has an AnimationThread. During construction the class does some standard plumbing to hookup the SurfaceHolder.Callback interface and starts the AnimationThread we looked at earlier. One of the parameters of the AnimationThread is an ISurface. This is where we can hook up our update and draw events to the animation thread. In this case we don't have to perform any logic for either event so they are left as empty functions. The final point of interest is surface creation or destruction. This will occur if your app goes out of focus for any reason. This could be because the user hit the home button, the app is being put to sleep, or the operation system is cleaning up memory for a larger foreground app. There are other reasons but those are the most common. In this case we have to make sure the thread no longer pumps animations and tries to draw to the canvas since the canvas will no longer exist. This is done by stopping the thread in the surfaceDestroyed callback. The thread is started in the surfaceCreated callback. This is the main reason for implementing the SurfaceHolder.Callback interface.

Finally edit the main activity class AndroidTutorial.java and replace the code with the following:

In this class we create an inner class called AndroidTutorialPanel which extends the DrawablePanel class we looked at above. Since DrawablePanel is an ISurace AndroidTutorialPanel overrides the ISurface members and provides custom implementation. In this case the class creates, updates, and draws an instance of an AnimatedSprite which we looked at previously. One point of interest is the creation of the sprite. The constructor expects a resource id, a resource height and width, and finally some timing values. These values control how many times per second the animation is drawn and how many frames to draw. You can use this to create many animations from a single sprite sheet and customize how fast those animations run.

Conclusion

You can easily extend this framework with your own panels or animation threads even. You can even customize your animation sprites how you see fit such as adding velocity, acceleration, or even a complete physics framework. There is no limit accept your own imagination.