LWJGL Best way to handle 2D Sprite Animations?

Hi, I’m wondering if there is a “recommended” way or something that would be better than what I’m currently doing.

My game currently has animations that are hundreds of frames, and there are hundreds of animations. I’m wondering if loading each of those frames as a separate image and then running those through a loop of some sort is the best way to do it.

Currently there is a spritesheet for each animation, that image is loaded as a BufferedImage, then the code splits it into individual BufferedImages for each frame, and adds them to the animation. It just seems like there is a much more efficient way to do this, perhaps some external library exists that makes animations easier.

I’ve entertained the idea of defining animations with XML or something like that, and loading the different limbs and bone structures of say a player, and having the code itself run through the animation rather than running through frames.

I’m not really seeing any performance issues doing this way, but it seems like there should be a better way.

Please don’t say use LibGDX, I’m making it from straight LWJGL as I’m more interested in learning the core stuff than finishing a complete game.

If you don’t want to go fully with LibGDX I would recommend Slick2D. It is very useful.

I have used Slick2D before, and I probably will for actually loading the images at some point, but right now I’m just wondering if there is a better way that anyone knows of to handle the actual animation other than just loading each frame as a separate image.

Look into skeletal animation.
Spine is a (probably) good tool for this, but looking at it at is least helpful to understand the concept.

Would this be able to work well with a physics library? I can’t think of a specific one I would use yet, but in theory would it be compatible with it(E.g. character get’s blown up and falls around places with limbs freely flailing), is that how that is commonly done?

Spine is a different concept, its for ragdoll animations n stuff - of course you can also use it to render those frame to images

@question: usually you use a spritesheet aka textureAtlas

like so:

Spine would reduce your need to have so many images, as well as allow you to have many more animations, including procedural animation (eg looking at the mouse).

The OP already stated that he has a spritesheet, but splits it into multiple separate images on the “java-side”.

This is not the right way to do it. Just load your complete spritesheet as one texture and change the texture coordinates of your Quad (or whatever you are using) to only contain the sprite frame you want to draw.

Take a look here: http://androidblog.reindustries.com/a-real-opengl-es-2-0-2d-tutorial-part-7-texture-atlas/ for inspiration

Thanks for the help guys. I think I may end up switching to LibGDX and using Spine. I currently will have over 10,000 animations if I keep doing it this way, and most likely many more than that. I think from what I’ve been Spine will be exactly what I need. Thanks for the advice.

This is how i do it, no LWJGL!



import java.awt.image.BufferedImage;

public class Animation {

	private BufferedImage[] animImages = {};
	private boolean animate = false;
	private int index = 0;
	private long miliSeconds, targetTime, now;

	public Animation(int mili,BufferedImage[] images) {
		this.miliSeconds = mili;
		animImages = images;
		now = System.currentTimeMillis();
		targetTime = now + miliSeconds;
		Main.anims.add(this);
	}
	
	public void stopAnimation(){
		animate = false;
	}
	
	public void startAnimation(){
		animate = true;
	}
	
	public BufferedImage getCurrentImage(){
		if(index < 0 || index > animImages.length){
			new Exception();
		}
		return animImages[index];
	}
	
	public void disposeAnimation(){
		Main.anims.remove(this);
	}
	
	public void setIndex(int i){
		index = i;
	}
	
	public void tick(){
		if (System.currentTimeMillis() >= targetTime && animate) {
			index++;
			now = System.currentTimeMillis();
			targetTime = now + miliSeconds;
			if(index>animImages.length-1){
				index = 0;
			}
		}
	}

}