In this post, we will cover how to make a 2d Animation for a sprite. Just make sure to grab all the necessary equipment like that animation tablet with screen.
Firstly we will need different sprites which would constitute the animation. Lets take for example we have 3 images Animation1.png, Animation2.png and Animation3.png.
First we would use TexturePacker discussed in the post Game Development in Android using Libgdx Part I to pack the textures in a single texture atlas. Then we would load the atlas using the following code
TextureAtlas textureAtlas; String TexturePath="Textures/"; String textureFile = TexturePath+"pack" ; textureAtlas= new TextureAtlas(Gdx.files.internal(textureFile), Gdx.files.internal(textureDir));
We will make a different TextureWrapper than the one in previous tutorials. Basically the draw function would be different so that it can also handle rotation of the sprite.
TextureWrapper
public class TextureWrapper{ public TextureRegion textureRegion; public Vector2 Position; int width; int height; float scaleX; float scaleY; int originX; int originY; public TextureWrapper(TextureAtlas atlas,String regionName,Vector2 pos){ //For above textures reigon names would be name of png like Animation1,Animation2 etc texture =atlasgetRegion(regionName). Position=pos; width=texture.getRegionWidth()/2; height=texture.getRegionHeight()/2; //Origin is the pivot for rotation. width/2 and height/2 set image's center as pivot for rotation originX=width/2; originY=height/2; scaleX=1; scaleY=1; } public void Draw(SpriteBatch sp){ sp.Draw(textureRegion, Position.x-width/2, //To position it in center horizontally Position.y-height/2, //To position it in center vertically originX, originY, width, //width of texture height, //height of texture scaleX, //Negative value will flip the texture horizontally scaleY //Negative value will flip the texture vertically Rotation //Rotation angle in degrees ); } }
So above method for drawing can be used to rotate ,scale ,flip the texture.
Basically, each frame can have two properties – first is the texture which should be drawn and second the length of time it should be drawn. So we will make a simple class to hold this information.
public class AnimationProperty{ public int Frame; public float TimeLimit; public AnimationProperty(int f,float t){ Frame=f; TimeLimit=t; } }
And now the animation class.
public class Animation{ public TextureWrapper[] textures; public Vector2 Position; public AnimationProperty[] animationProperty; int currentFrame; int animationCycles; float ticker; float timeLimit; Boolean paused; public Animation(int numberOfTextures,Vector2 pos){ textures=new TextureWrapper[numberOfTextures]; Position=pos; } public void AddFrame(TextureAtlas atlas,String regionName,int index){ textures[index]=new TextureWrapper(atlas,regionName,Position); } public void Set(int frame){ currentFrame=(currentFrame+1)%animationProperty.length; timeLimit=animationProperty[currentFrame].TimeLimit; ticker=0; } public void SetAnimationProperty(AnimationProperty[] anim){ animationProperty=anim; Set(0); } public void Update(float dt){ if(!paused){ ticker+=dt; if(ticker>timeLimit){ ticker-=timeLimit; currentFrame=(currentFrame+1)%animationProperty.length; timeLimit=animationProperty[currentFrame].TimeLimit; if(currentFrame==0) animationCycles++; } } } public void Draw(SpriteBatch sp){ int texFrame=animationProperty[currentFrame].Frame; textures[texFrame].Draw(sp); } }
In the above class we hold textures in one array and their properties in another. In update we increment time and check if time limit for the frame has crossed or not. If it is crossed then we load the next frame. If current frame crosses the last frame then it goes back to the first and we increase the cycle count. So if you want to run the animation once then check if the cycle count is equal to 1 to halt the animation.
Mostly for one particular set of textures their animation is similar so we make global array of animation property and pass that reference to all the animations we instantiate.
//Texture constants static int ANIMATION1_TEXTURE=0; static int ANIMATION2_TEXTURE=1; static int ANIMATION3_TEXTURE=2; //Animation Property constants static int ANIMATION_FRAME_1=ANIMATION1_TEXTURE; static int ANIMATION_FRAME_2=ANIMATION2_TEXTURE; static int ANIMATION_FRAME_3=ANIMATION3_TEXTURE; static int ANIMATION_FRAME_4=ANIMATION2_TEXTURE; static float ANIMATION_FRAME_TIME_1=0.5f; static float ANIMATION_FRAME_TIME_2=0.2f; static float ANIMATION_FRAME_TIME_3=0.2f; static float ANIMATION_FRAME_TIME_4=0.2f; //Animation Property AnimationProperty[] globalProperty1=new AnimationProperty[4]; globalPoperty1[0]=new AnimationProperty(ANIMATION_FRAME_1,ANIMATION_FRAME_TIME_1); globalPoperty1[1]=new AnimationProperty(ANIMATION_FRAME_2,ANIMATION_FRAME_TIME_2); globalPoperty1[2]=new AnimationProperty(ANIMATION_FRAME_3,ANIMATION_FRAME_TIME_3); globalPoperty1[3]=new AnimationProperty(ANIMATION_FRAME_4,ANIMATION_FRAME_TIME_4); //Initialize Animation Animation testAnimation=new Animation(3,new Vector2(10,10)); testAnimation.AddFrame(atlas,"Animation1",ANIMATION1_TEXTURE); testAnimation.AddFrame(atlas,"Animation2",ANIMATION2_TEXTURE); testAnimation.AddFrame(atlas,"Animation3",ANIMATION3_TEXTURE); testAnimation.SetAnimationProperty(globalProperty1);
In this way we can initialize the animation. The above example will the draw Animation1.png for 0.5 seconds, then Animation2.png for 0.2 seconds, then Animation3.png for 0.2 seconds and then Animation2.png again for 0.2 seconds. This cycle of textures would repeat with time.
Hopefully this will give you a direction into how to animate a 2d sprite.
Let us know any of your doubts/suggestions; please put them in the comments section and we would try to answer them.
Thank you for the patience.
Looks like i have found a treasure on Libgdx finally, was looking for a start for learning libgdx and here it is. Hopefully as soon as i complete all of these articles here, i will have more to read. can you please write on Level design, and tile and actor collisions?
Glad to know you find it useful. Well we use box collision so we never had to handle tile collisions ourselves, just let box handle the physics part