In order to make anything more than very simple games in 2D it’s important to be able to draw animated sprites.
There are several ways to create animated sprites in Android, including using XML based declarations and swapping between multiple bitmaps. But when I came to write my animation code neither of these methods was flexible enough for the kind of animation I needed.
Instead of using these methods I instead used sprite sheets and the functionality provided by the Android bitmap drawing functions to draw each frame of the animation. In a nutshell each frame of animation is set on a single bitmap one after the other. The animation code then plays one frame after the other until the animation is complete. Below is an example of a sprite of a bouncing color changing arrow.

Note: Sprites are not to be confused with just “Pixel Art” style images. Sprites in graphics programming typically refer to any image used in games.
Assuming you have been following the earlier tutorials on 2D programming here then you already have all the basic knowledge you need to set up a project ready to handle full sprite animation. So I’ll skip ahead and assume you already have a thread setup to control the animation.
We first need to add a new class to our project which will represent an animated sprite within our game. Below is the class variables needed to setup and control the animation. I’ll go through each one in turn.
1 2 3 4 5 6 7 8 9 10 11 | public class OurAnimatedSpriteClass { private Bitmap mAnimation; private int mXPos; private int mYPos; private Rect mSRectangle; private int mFPS; private int mNoOfFrames; private int mCurrentFrame; private long mFrameTimer; private int mSpriteHeight; private int mSpriteWidth; |
1 | mAnimation |
This is the variable which will hold the actual bitmap containing the animation. You may wonder why I keep it in this class rather than as a variable of the thread running the animation. Firstly it’s to keep the thread class clean and easy to read by not cluttering it up with hundreds of variables like this. Secondly it is to maintain encapsulation which is a software development technique which means that each class is responsible for itself and nothing else. I recommend doing some reading on encapsulation if you are new to programming.
1 | mXPos/mYPos |
These hold the X and Y screen coordinates for where we want the sprite to be on the screen. Don’t forget that these refer to the top left had corner of the image and not the centre.
1 | mSRectangle |
This is the source rectangle variable and controls which part of the image we are rendering for each frame. This will be explained in more detail later.
1 | mFPS |
This is the number of frames we wish to show per second. 15-20 FPS is enough to fool the human eye into thinking that a still image in moving. However on a mobile platform it’s unlikely you will have enough memory to keep enough sprites to have totally smooth animation at 30FPS for a full game so typically this is between 3 – 10 FPS which is fine for most needs.
1 | mNoOfFrames |
This is simply the number of frames in the sprite sheet we are animating.
1 | mCurrentFrame |
We need to keep track of the current frame we are rendering so we can move to the next one in order.
This controls how long between frames. Note that this is a long and not an int for reasons which will be explained later.
1 | mSpriteHeight/mSpriteWidth |
These contain the height and width of an Individual Frame not the entire bitmap and are used to calculate the size of the source rectangle.
Now that’s over we can get to the interesting coding.
First add a quick constructor to set up some default values.
1 2 3 4 5 6 7 | public OurAnimatedSpriteClass() { mSRectangle = new Rect(0,0,0,0); mFrameTimer =0; mCurrentFrame =0; mXPos = 80; mYPos = 200; } |
Nothing exciting yet but the next function is better.
1 2 3 4 5 6 7 8 9 10 11 | public void Initalise(Bitmap theBitmap, int Height, int Width, int theFPS, int theFrameCount) { mAnimation = theBitmap; mSpriteHeight = Height; mSpriteWidth = Width; mSRectangle.top = 0; mSRectangle.bottom = mSpriteHeight; mSRectangle.left = 0; mSRectangle.right = mSpriteWidth; mFPS = 1000 /theFPS; mNoOfFrames = theFrameCount; } |
Above is the Initialize function. As you can see it takes a lot of arguments but it is quite simple. Firstly it provides the Bitmap for use in the animation (I’ll show you how to pass a bitmap as an argument later).Next it sets up the height and width of a single frame and then moves onto the source rectangle. As explained above the source rectangle controls which part of the image we want to draw at any given time. To start with you want this to be the first frame. So the rectangle is setup to start at 0, 0 and be the same height and width of the first frame.
The next variable to be setup is the FPS. Now you may wonder why this value is 1000/FPS. This is because the frame timings are done in milliseconds. If the frame rate is 10 FPS you want the frame changed every 1/10th of a second or 1000/10 in milliseconds. Finally it also sets up the frame count to the number of frames of animation.
Now you may be asking how do we change what frame is shown?
To do that we need to add another function, the update function.
1 2 3 4 5 6 7 8 9 10 11 12 13 | public void Update(long GameTime) { if(GameTime > mFrameTimer + mFPS ) { mFrameTimer = GameTime; mCurrentFrame +=1; if(mCurrentFrame >= mNoOfFrames) { mCurrentFrame = 0; } } mSRectangle.left = mCurrentFrame * mSpriteWidth; mSRectangle.right = mSRectangle.left + mSpriteWidth; } |
The update code is actually very very simple and only takes a few lines. You’ll notice that a variable called Game Time is in the argument list. This variable is used to track the amount of time that has elapsed. We use this variable to decide if it’s time to change frames yet.
1 2 3 | if(GameTime > mFrameTimer + mFPS ) { mFrameTimer = GameTime; mCurrentFrame +=1; |
This is the code that does the checking. If the Game time variable is greater than the frametimer + the FPS then what that means is that the amount of time FPS is set to has elapsed and which case is time to change frames.
If it’s a little hard to get your head around how it works but if you code it up and have a look in the debugger it will make more sense. If it is time to change frames then the frame timer is reset to the current game time and the current frame is incremented.
1 2 3 | if(mCurrentFrame >= mNoOfFrames) { mCurrentFrame = 0; } |
This part of the code above is to make sure that if we have ran out of frames we go back to the beginning. If you don’t want that to happen you could switch to another animation or handle it however you like here.
This next code is where the magic happens and the actual code is surprising simple.
1 2 | mSRectangle.left = mCurrentFrame * mSpriteWidth; mSRectangle.right = mSRectangle.left + mSpriteWidth; |
This code makes sure that the source rectangle is showing the right frame. This is updated by multiplying the sprite width by the current frame to get the left most boundary of the frame and adding the sprite width onto this value to get the right most boundary. Again if this is confusing have a look in the debugger about what’s actually happening.
All that remains now is to draw the correct frame in the correct place. We do that with the draw function below.
1 2 3 4 5 6 | public void draw(Canvas canvas) { Rect dest = new Rect(getXPos(), getYPos(), getXPos() + mSpriteWidth, getYPos() + mSpriteHeight); canvas.drawBitmap(mAnimation, mSRectangle, dest, null); } |
First we need to create a destination rectangle. This will be where the sprite is to be rendered on the canvas. So assuming you set the position with the X and Y positions as above you can just set the sprite height and width to be the bottom and right values respectively and you have the right sized source rectangle.
Finally it just needs drawing. To do this you only need to call the draw Bitmap command on the canvas that is passed as an argument. The function only requires the bitmap to display, the source and destination rectangles we already created and the last value can be set to null.
Now in order to use this class you have to add a few things in your graphics thread. First declare a new variable of your class and then it can be initialised in the constructor as below.
1 2 | Animation = new OurAnimatedSpriteClass(); Animation.Initalise(Bitmap.decodeResource(res, R.drawable.idle), 200, 150, 5, 5); |
In order to pass the value of the bitmap you first have to use the Bitmap Factory class to decode the resource. It decodes a bitmap from your resources folder and allows it to be passed as a variable. The rest of the values depend on your bitmap image.
In order to be able to time the frames correctly you first need to add a Game timer to the game code. You do this by first adding a variable to store the time as show below.
1 | private long mTimer; |
We now need this timer to be updated with the correct time every frame so we need to add a line to the run function to do this.
1 2 3 4 | public void run() { while (mRun) { Canvas c = null; mTimer = System.currentTimeMillis(); |
The line above will make sure the time is always correct.
We also need to update the animation every game tick so add another line to your run function.
try { c = mSurfaceHolder.lockCanvas(null); synchronized (mSurfaceHolder) { Animation.update(mTimer); doDraw(c); }
The update function is now called with the correct time so it will always display the right frame. now all we have to do is add the function call to draw the animation.
1 | Animation.draw(canvas); |
Add this line to your Draw function and the animation will draw the current frame in the right place.
And that’s all there is too it, add any questions in the comments and let me know if there’s any other game programming concepts you need help with in Android. Happy coding.
Stephen Flockton, Toxic Tower Studios
Final note: This code is based on app being able to run at full speed at all times. If you have a lot of graphics you may get slow down on your animations as they are not updating fast enough. For this case it is important to add a fixed time step to your code to deal with animations running too slow or fast.
Comments
Leave a comment Trackback