/** * An {@link AnimatedSprite} holds an {@link Animation} and sets the {@link Texture} of its super type {@link Sprite} to the correct one according to the information in the {@link Animation}. * Usage: * <pre>Animation animation = new Animation(1 / 3f, new TextureRegion(frame1), new TextureRegion(frame2), new TextureRegion(frame3));animation.setPlayMode(Animation.LOOP);animatedSprite = new AnimatedSprite(animation);</pre> * Draw it using any of the {@link Sprite Sprite's} draw methods:<pre>animatedSprite.draw(batch);</pre> * * @author dermetfan */public class AnimatedSprite extends Sprite {

/** the {@link Animation} to display */ private Animation animation;

/** the current time of the {@link Animation} */ private float time;

/** if the animation is playing */ private boolean playing = true;

/** if the animation should be updated every time it's drawn */ private boolean autoUpdate = true;

/** if the size of the previous frame should be kept by the following frames */ private boolean keepSize;

/** if a frame should be centered in its previous one's center if it's smaller */ private boolean centerFrames;

/** * creates a new {@link AnimatedSprite} with the given {@link Animation} * @param animation the {@link #animation} to use */ public AnimatedSprite(Animation animation) { this(animation, false); }

/** * An {@link AnimatedSprite} holds an {@link Animation} and set's the {@link Texture} of its super type {@link Sprite} to the correct one according to the information in the {@link Animation}. * Usage: * <pre>Animation animation = new Animation(1 / 3f, new TextureRegion(frame1), new TextureRegion(frame2), new TextureRegion(frame3));animation.setPlayMode(Animation.LOOP);animatedSprite = new AnimatedSprite(animation);</pre> * Draw it using any of the {@link Sprite Sprite's} draw methods:<pre>animatedSprite.draw(batch);</pre> * * @author dermetfan */public class AnimatedSprite extends Sprite {

/** the {@link Animation} to display */ private Animation animation;

/** the current time of the {@link Animation} */ private float time;

/** if the animation is playing */ private boolean playing = true;

/** if the animation should be updated every time it's drawn */ private boolean autoUpdate = true;

/** if the size of the first frame should be kept by the following frames */ private boolean keepSize;

// draw it by calling any of the Sprite's draw methodsanimatedSprite2.draw(batch);

......

animatedSprite5000.draw(batch);

If you did it like this, you would have 5000 individually playing animations, each holding their own Animation with its own TextureRegions, indeed causing alot extra overhead.

Assuming the animation should be the same for all enemies, you could create one Animation and pass it into the AnimatedSprite constructor. This will result in 5000 AnimatedSprite instances, each holding a pointer to the Animation which holds the TextureRegions. This way, you just have the Animation and TextureRegions once, causing no extra overhead.

// create one Animation for all enemiesAnimation animation = new Animation(1 / 3f, new TextureRegion(frame1), new TextureRegion(frame2), new TextureRegion(frame3));animation.setPlayMode(Animation.LOOP);

// create the individually playing AnimatedSpritesanimatedSprite1 = new AnimatedSprite(animation);animatedSprite2 = new AnimatedSprite(animation);animatedSprite3 = new AnimatedSprite(animation);

The 5000 AnimatedSprite instances each hold a pointer to the Animation, but they still hold their own time variable and three booleans. This is absolutely no problem at all, and even necessary if you want your animations to play individually.

If you want to save as much memory as possible, you could even go one step furter and create one AnimatedSprite for all enemies. Because each enemy updates the Animation when drawing by default, the Animation is played 5000 times faster, so you have to update it manually. That's a good way if it's ok to have the same animation state for every enemy.

// create one AnimatedSprite for all enemiesAnimation animation = new Animation(1 / 3f, new TextureRegion(frame1), new TextureRegion(frame2), new TextureRegion(frame3));animation.setPlayMode(Animation.LOOP);animatedSprite = new AnimatedSprite(animation);animatedSprite.setAutoUpdate(false);

// set the one animation to all the enemiesenemy1.setSprite(animatedSprite);enemy2.setSprite(animatedSprite);

// update the AnimatedSprite for all the enemies@Overridepublic void render(float delta) { animatedSprite.update(delta);}

Another big problem with this approach is that all the other attributes of the AnimatedSprite such as position, with and height are the same, too.When using animatedSprite#draw(SpriteBatch), it will draw them all at the same position. You'd have to store necessary information (e.g. position) in your enemy class and set the AnimatedSprite one's to it every time you draw.Or you update the AnimatedSprite using animatedSprite.update() and draw it using the batch:

// draw it by calling any of the Sprite's draw methodsanimatedSprite2.draw(batch);

......

animatedSprite5000.draw(batch);

If you did it like this, you would have 5000 individually playing animations, each holding their own Animation with its own TextureRegions, indeed causing alot extra overhead.

Assuming the animation should be the same for all enemies, you could create one Animation and pass it into the AnimatedSprite constructor. This will result in 5000 AnimatedSprite instances, each holding a pointer to the Animation which holds the TextureRegions. This way, you just have the Animation and TextureRegions once, causing no extra overhead.

// create one Animation for all enemiesAnimation animation = new Animation(1 / 3f, new TextureRegion(frame1), new TextureRegion(frame2), new TextureRegion(frame3));animation.setPlayMode(Animation.LOOP);

// create the individually playing AnimatedSpritesanimatedSprite1 = new AnimatedSprite(animation);animatedSprite2 = new AnimatedSprite(animation);animatedSprite3 = new AnimatedSprite(animation);

The 5000 AnimatedSprite instances each hold a pointer to the Animation, but they still hold their own time variable and three booleans. This is absolutely no problem at all, and even necessary if you want your animations to play individually.

If you want to save as much memory as possible, you could even go one step furter and create one AnimatedSprite for all enemies. Because each enemy updates the Animation when drawing by default, the Animation is played 5000 times faster, so you have to update it manually. That's a good way if it's ok to have the same animation state for every enemy.

// create one AnimatedSprite for all enemiesAnimation animation = new Animation(1 / 3f, new TextureRegion(frame1), new TextureRegion(frame2), new TextureRegion(frame3));animation.setPlayMode(Animation.LOOP);animatedSprite = new AnimatedSprite(animation);animatedSprite.setAutoUpdate(false);

// set the one animation to all the enemiesenemy1.setSprite(animatedSprite);enemy2.setSprite(animatedSprite);

// update the AnimatedSprite for all the enemies@Overridepublic void render(float delta) { animatedSprite.update(delta);}

Another big problem with this approach is that all the other attributes of the AnimatedSprite such as position, with and height are the same, too.When using animatedSprite#draw(SpriteBatch), it will draw them all at the same position. You'd have to store necessary information (e.g. position) in your enemy class and set the AnimatedSprite one's to it every time you draw.Or you update the AnimatedSprite using animatedSprite.update() and draw it using the batch:

Just would like to ask one more question: How can I judge if the Animation is finished in AnimatedSprite? I tried using isPlaying(), while seems not work, anything I missed? Or should I use the isAnimationFinished(stateTime) in the Animation class? If yes, what the stateTime should be? (Now I am using the Animation.NORMAL mode)

For below scenario, not sure if I met a bug: If there is more Enemy instances, the Animation will showing faster and faster! (animation duration will be shorter, and using Animation.LOOP) enemy1 = new Enemy(type2AnimatedSprite); enemy2 = new Enemy(type2AnimatedSprite); ..... enemy300 = new Enemy(type2AnimatedSprite);

--------------------“for simultaneously playing animations: use ONE Animation for ONE AnimatedSprite for all enemies (watch out, other attributes of the Sprite are the same as well!)”

dermetfan wrote:If you want to save as much memory as possible, you could even go one step furter and create one AnimatedSprite for all enemies. Because each enemy updates the Animation when drawing by default, the Animation is played 5000 times faster, so you have to update it manually. That's a good way if it's ok to have the same animation state for every enemy.

// create one AnimatedSprite for all enemiesAnimation animation = new Animation(1 / 3f, new TextureRegion(frame1), new TextureRegion(frame2), new TextureRegion(frame3));animation.setPlayMode(Animation.LOOP);animatedSprite = new AnimatedSprite(animation);animatedSprite.setAutoUpdate(false);

// set the one animation to all the enemiesenemy1.setSprite(animatedSprite);enemy2.setSprite(animatedSprite);

// update the AnimatedSprite for all the enemies@Overridepublic void render(float delta) { animatedSprite.update(delta);}

It looks like you modified my example code (because of type2AnimatedSprite). Don't forget that there were these lines in it:

If you know how many enemies you'll have and their number won't change, you could also set a frame duration that is the according time slower. I wouldn't usually recommend this, though.For example, if you have and always will have 300 enemies and the frame duration should be a third of a second, you could set it to 1 / 3f * 300. This means you have to update 300 times to get past the same duration, which the 300 enemies will do for you, because each enemy updates the AnimatedSprite once individually.