Sprite Animation

Hey ive been doing some tutorials for Sprite Animation, & i have made an animation but my fps goes down really low & it just slows down the program in general.
I first thought it was BufferedImage but change it but still made no no difference. I’ll post the main part that is making it lag so much (its updating each image).

//Updating the animation image
public void update(long time) {
		if (running) {
			if (time - previousTime >= speed) {
				currentFrame++;
				if (currentFrame < frames.size()) {
					sprite = frames.get(currentFrame); <<< main part of the lag
				} else {
					currentFrame = 0;
					sprite = frames.get(currentFrame);
				}
				previousTime = time;
			}
		}
	}

//updating the animation on screen
public void update(Display display) {
			animation.update(System.currentTimeMillis());
		
	}

Thanks for taking a look :slight_smile:

how do you render you “sprite” variable? Are you sure this is the slow spot?
What is you frames.get() method doing? Or is it just a plain Vector/LinkedQueue?

What is your display doing as a parameter for your update-method?

And how come you do a new call to System.currentTimeMillis() in every animation?
It would be better to have an update-method in the class holding the animations, which sends the time-difference to all animations in a for-loop. Then you only need to do 1 call to System.currentTimeMillis() for every frame, instead of once per animation.

And, as teletubo wrote, we’d need to see more code. Especially the way you render the sprite.

This is how my current code works:

I have a screen manager & a display you input the display that you want to show, so it updates from the display from the screen manager here is the code:

private void render() {
		BufferStrategy bs = getBufferStrategy();

		if (bs == null) {
			createBufferStrategy(2);
			return;
		}

		Graphics g = bs.getDrawGraphics();
		g.fillRect(0, 0, frame.getWidth(), frame.getHeight());
		screen.paintStage(g);
		screen.updateStage(this);
		g.dispose();
		bs.show();
	}
public void paintStage(Graphics g){
		if(currentState == Stage1Name){
			Stage1.paint(g);
		}
	}
	
	public void updateStage(Display display){
		if(currentState == Stage1Name){
			Stage1.update(display);
		}
	}

& i have an ArrayList for BufferedImage this is getting the current image really. -

public BufferedImage sprite;
	private ArrayList<BufferedImage> frames = new ArrayList<BufferedImage>();
	private boolean running = false;
	private long previousTime, speed;
	private int frameAtPause, currentFrame;

	public void update(long time) {
		if (running) {
			if (time - previousTime >= speed) {
				currentFrame++;
				if (currentFrame < frames.size()) {
					sprite = frames.get(currentFrame);
				} else {
					currentFrame = 0;
					sprite = frames.get(currentFrame);
				}
				previousTime = time;
			}
		}
	}

I know this is “sprite = frames.get(currentFrame);” the problem because when i comment it out it goes from 90 odd fps to 1000 odd fps.
Thanks taking the time to look :slight_smile:

There is no telling from the snippets without the whole context.
The ArrayList-get isn’t the cause for sure, probably it gets faster cause you dont render anything when commented.

Here is the main parts of my animation which i use to add the animation & get all the information i need to get it working. -

Animation class

public BufferedImage sprite;
	private ArrayList<BufferedImage> frames = new ArrayList<BufferedImage>();
	private boolean running = false;
	private long previousTime, speed;
	private int frameAtPause, currentFrame;

	public void update(long time) {
		if (running) {
			if (time - previousTime >= speed) {
				currentFrame++;
				if (currentFrame < frames.size()) {
					sprite = frames.get(currentFrame);
				} else {
					currentFrame = 0;
					sprite = frames.get(currentFrame);
				}
				previousTime = time;
			}
		}
	}

	public Animation(ArrayList<BufferedImage> frames) {
		this.frames = frames;
	}

	public void setSpeed(long speed) {
		this.speed = speed;
	}

	public void play() {
		running = true;
		previousTime = 0;
		frameAtPause = 0;
		currentFrame = 0;
	}

	public void stop() {
		running = false;
		previousTime = 0;
		frameAtPause = 0;
		currentFrame = 0;
	}

	public void pause() {
		frameAtPause = currentFrame;
		running = false;
	}

	public void resume() {
		currentFrame = frameAtPause;
		running = true;
	}
}

BufferedImageLoader Class -

public BufferedImage loadImage(String pathRelativeToThis) throws IOException {
		URL url = this.getClass().getResource(pathRelativeToThis);
		BufferedImage img = ImageIO.read(url);
		return img;
	}

SpriteSheet -

public BufferedImage spriteSheet;
	
	public SpriteSheet(BufferedImage ss){
		this.spriteSheet = ss;
	}
	
	public BufferedImage grabSprite(int x, int y, int width, int height){
		BufferedImage sprite = spriteSheet.getSubimage(x,  y,  width,  height);
		return sprite;
	}

cheers for taking the time to look :slight_smile:

Hmm, that all looks like it’ll work fine.

The only thing I can think of that would make that kind of a difference, is if you for some reason load or subimage everything every update, but I can’t see that from the snippets you’ve posted.

Are you remembering to get a compatible image to render to? A few weeks ago a guy on this forum told me to load all my images using this (code below). I thought he was a mad man, but it turned out it lowered my load- and render-times significantly. Probably won’t help your particular problem though. Make sure you’re not loading your images every update. Can’t really see what else it could be.

Try using this to load all your spritesheets through, like this: BufferedImage img = toCompatibleImage(ImageIO.read(url));


private BufferedImage toCompatibleImage(BufferedImage image)
	{
	        // obtain the current system graphical settings
	        GraphicsConfiguration gfx_config = GraphicsEnvironment.
	                getLocalGraphicsEnvironment().getDefaultScreenDevice().
	                getDefaultConfiguration();

	        /*
	         * if image is already compatible and optimized for current system 
	         * settings, simply return it
	         */
	        if (image.getColorModel().equals(gfx_config.getColorModel()))
	                return image;

	        // image is not optimized, so create a new image that is
	        BufferedImage new_image = gfx_config.createCompatibleImage(
	                        image.getWidth(), image.getHeight(), image.getTransparency());

	        // get the graphics context of the new image to draw the old image on
	        Graphics2D g2d = (Graphics2D) new_image.getGraphics();

	        // actually draw the image and dispose of context no longer needed
	        g2d.drawImage(image, 0, 0, null);
	        g2d.dispose();

	        // return the new optimized image
	        return new_image; 
	}

What I do for my animations, is to use no actual images, but String-references, so when I add a new frame, it just says “Monster1Walking1” and “Monster1Walking2”.
The animations work just like yours, but when I draw them, I do something like g.drawImage(monsterImages.get(monster.getCurrentImage()), posX, posY, null);
where my monsterImages variable is a HashMap of BufferedImages with Strings as key, and when I do getCurrentImage on my monster, I get the String representing the image-reference String in the frame that the monsters’ animation is currently at.
This ensures that I never have more than one instance of each image in memory at any time, and then I can take care of ANY loading and subimaging when setting up the monsterImages HashMap. You see what I mean? That helps me split everything up in modules, so I know if the animations screw up, the Animation-class is to blame, and if the images screw up, it is the loading of them that is to blame, or my references are wrong. Makes it wasier to check for errors, and much easier to build modules to take care of the different sections.