Android Development

2D Sprite Animation in Android

by Stephen Flockton on Sep.13, 2009, under tutorial

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.

Arrow Spritesheet

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.

  • Share/Bookmark
:, , ,

25 Comments for this entry

  • Ismael

    Thank you for your tutorial. Do you have any game with this source code?
    You could make a post with a menu with animated buttons for a game.

    Regards,
    Ismael

  • sherlockhua

    firstly,thank you for good article.
    I have a question on how to interact with the player,can you give me some help or give me some example, my email
    is sherlockhua [at] 163 [dot] com
    thanks again.
    [info from Martin]To prevent spam, i changed your email a bit :)

  • Stephen Flockton

    @Ismael: The only full game I have using this source code is the one I intend to release on app market soon, so can’t release the entire source code just yet.

    I will code one up in the course of the tutorials i should imagine. As for Animated Buttons what exactly do you mean. Buttons that flash and move? , or buttonns which change when you press them?.

    @Sherlockhua: What kinda of interaction are you looking for? using Buttons or touch screen support? If you let me know then I can make a tutorial for it so everyone can benefit.

    Stephen

  • Ismael

    Hi, I understand. We will buy your app.

    I want to program the typical menu before a game: play/continue, ratings, options, credits (using touch screen, which change when you press them)
    And it use the graphics and font of the game.

    Thanks again.

  • Thomas

    Very good Stephen!

    Ismael, you says:
    http://www.rbgrn.net/sites/default/files/images/Wixel-Main-Menu.jpg
    Can you explain this?

    Thanks!

  • sherlockhua

    thank you for reply.I’m have some question about the key input.Each time update the game state,i should get the key state then process the user input,but how can i get a state of key? In j2me,we can use getkeyState function,but android I can’t find a similar one?

  • Martin

    The state of the key is more the action here.
    KeyEvent.ACTION_DOWN or KeyEvent.ACTION_UP is what you are looking for. Check this: KeyEvent Documentation

  • Stephen Flockton

    @Sherlockhua: I would also reccomend the Luna Lander Example from the Android SDK. It has a very good implmentation of how to deal with button presses.

    @Ismael & Thomas: Since it seems that creating a menu system is a popular request. I’ll make a tutorial for it next. Keep checking the site and it’ll be up in a few days I imagine.

  • Honte

    I would like to know if there is a decent sprite editor for linux. The code part is clear, but, how do you manage to get the “metadata”? I mean, for each bitmat, the number of frames and size of the sprite. I was thinking in coding one in Qt that generates a xml with the bitmap names and their sizes .. but I think that 2D games have been around for years, and, there must be some good sprites editors around ?
    I don’t want to reinvent the wheel, and lose my time with the tools.

  • Stephen Flockton

    @Honte: I’ve never had a problem finding out the “metadata” since we have artists who make the spritesheets in Photoshop.

    If you already have the sprite sheet its a simple matter of opening up the thing in an image editor and just looking it up.

    If you want to make a sprite sheet from a bunch of images then there are loads of utility’s that will do that, just a quick goggle can find a few.

    Hope this helps

  • K Diddy

    Hi Martin,

    Is your code here cycling through images or is the R.drawable.idle a single image that is moving?

    I didn’t see any other reference to other pictures that it would cycle through when drawing.

    Thanks,
    K

  • Martin

    Again, this post is made by Stephen.
    Have you take a look into the drawable directory? The answer should be there.

  • Stephen Flockton

    Hi K Diddy,

    R.drawable.idle is a sprite sheet. That is its one image with several frames of Animation contained in it.(Just like the image of the arrows at the top of the post).

    The code cycles through each of these frames in turn.

    Hope that answers your question.

    @Martin:

    I did not actually include any downloadable source code for this. I’ll create a sample project for it when I have time.

  • K Diddy

    Thanks Stephen,

    Do you know where I can go to learn how to make good sprite sheets? I’m having an issue finding any tutorials.

    Thanks,
    K

  • Stephen Flockton

    Hi K Diddy,

    Do you mean learning how to draw them or how to create them from images you already have?

    Stephen

  • Sasikumar

    Hi,

    I can’t able to understand how to make this code as projetc?…
    can u pls give the full source code…
    my mail id is :- msg2sasikumar@gmail.com

  • BenL

    Hi there.

    Im stuck on this line here:

    if(GameTime > mFrameTimer + mFPS ) {

    and here:

    if(mCurrentFrame >= mNoOfFrames) {

    Eclipse say’s there’s no variable for gt and im not sure how to do this. Like, do I declare gt somewhere in the class as an object declaration or something?

    also in the second line im stuck on >= gives me a syntax error and i dont know how to fix it without introducing more errors in this function.

    Can you help please? thanks.

  • Martin

    Hi,
    sorry, this was a copy & paste error. Wordpress can change special characters sometimes.
    I fixed this in the post. Change every & gt; to > and every & lt; to < and it should work.
    Or simply look at your comment, because Wordpress already changed what you posted to the right characters :)

  • BenL

    Oh yes, i just noticed lol. Thank you :)

  • BenL

    hi sorry again,

    ive reached up onto:

    public void draw (Canvas canvas) {
    Rect dest = new Rect(getXPos(), getYPos(), getXPos() + mSpriteWidth,
    getYPos() + mSpriteHeight);

    canvas.drawBitmap(mAnimation, mSRectangle, dest, null);
    }

    of the tutorial. Eclipse has problems with the getYPos() etc method calls, does this mean this sprite tutorial has assumed the programmer has written their own thread & graphic class seperately already? im quite lost …

    many thanks.

  • Stephen Flockton

    GetXPos() and getYPos() are just simple get methods sir.
    I don’t include them in the outline because I assumed most people reading would know that.

    I apologise and will see about uploading the full source if I can.

    Stephen

  • BenL

    ah i see, apologies for my noobness haha. But yes if you could then that would be useful 8D Many thanks!

  • Wilson

    Wow, nice tutorial, but I am wondering, how could I add in more sprites in this canvas?

    This is my method, it doesn’t work:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    animation2.setXPos(0);
    animation2.setYPos(0);
    animation2.update(mTimer);
    animation2.draw(c);
     
    animation3.setXPos(50);
    animation3.setYPos(0);
    animation3.update(mTimer);
    animation3.draw(c);
  • Wilson

    I solved the problem, because I set canvas.drawColor(Color.BLACK);
    in my draw method.

    But after I removed that, I it won’t clear the sprites, as in there are multiple images in a sprite, is there any way to clear the sprite before it draws the new frame?

  • Rootko

    @Wilson – you probably figured out by now, but it depends on what is the order in draw() respectively in Thread that draws – first call onDraw() of SurfaceView, then draw your animation ;)

Leave a Reply