[Java 2D Character Animation]

Hello guys, this is my FIRST post on these forums!, just simply googled java programming forums and hey, here I am :), hope to stay, get information/help/tips, and also deal them.

Well my problem is with my new 2D java game, it’s very simple contains a background, the sprites for all types of character movement, that’s about it at the moment.

I have the basics setup, you know…
Draw the map background, draw the character, keyListeners, you know if left key is down than obviously the characters position would move absX–;, and than it will draw a new Sprite/ImageIcon which looks like one of these:

There are a total of six Sprites for when the character is walking down the screen, so here is where my problem/call for advice is coming into play:

I would like to post a couple of snippets first very brief, just showing you guys how the animation is being added at the moment.

The first snippet is coming from the keyPressed() method, for when the character is moving down:


        if (i == 40) { //Down
        	downPressed = true;
			if (h >= 300) { canMove = false; return; } //Stopping the character from going off the screen.
			Sprite = walkFront1.getImage();
			h++;
        }

The method as you can see for grabbing the sprite is this “Sprite = walkFront1.getImage();”, which simply returns a ImageIcon and the path of the file.

The second method is the paint(Graphics g), which is located in the frames class.
(Note: the code shown was subtracted from the only contents are the ones for the movement down)


	public void paint(Graphics g) {
		super.paint(g);
		Graphics2D g2d = (Graphics2D) g;
		g2d.drawImage(p.getImage(), p.absX, p.absY, null);
	}

The p.getImage(), which is in the Player class, was defined earlier from the “Sprite = walkFront1.getImage();” + the path for the image.

So my question here is what would I have to do to add in a Animation process, 5-6+ steps, simply being called upon whenever the player is moving in that direction, possibly detecting as long as that key is held down, do that process.
I was thinking about creating a sub Thread, which would just simply sleep, detect what keys are held down and what are not, than do a animation, and loop through that until it the keyPressed was released.

I’m 17, and i’m just now starting to get serious about Java programming, possibly after my GED go into College or take further action into learning about it.

Please give me some feedback guys would be great.

In an update method, if you dont have one you should, you call it once every frame right?

So why not just poll if a each key is pressed at that time and act upon it(i.e. x++ for right key press)

And in reply to your threads idea… don’t. Just don’t. Threads are not necessary for that kind of thing, they just complicate the process, the JVM is more than capable of running your game smoothly in one thread. An example of employing threads is for a multiplayer server which needs to handle heaps of players and world/game updates at once.

Do you have any idea about how i would go in doing that? :o
That’s why i’m here, yes every frame I could check if a key is held down by setting a boolean to true when that key is held down, but than what would i do to make it ‘timely’ shift Sprites?

Hey there!

I’m really new in game programming, but I think I can help. What I do is the following (you can see an old but functional engine I used for Ludum Dare 22 here). My game loop looks (in a simplified way) like this:

while(!exitRequested) {
    // some code

    Game.update(delta);
    Game.draw(delta);

    // some code
}

Game is a class that ensures that every entity (player, enemies, decorations) gets updated and drawn on screen. In Game.update(delta), delta is the number of milliseconds since last frame so the game goes at the same apparent speed in every platform. Do not pay attention to that right now.

All my entities have a custom class called Sprite. Sprite allows inserting animations (method insertAnimation()) setting animations, and updating. An animation is basically a texture (image) with all the steps in the animation and the information on how to extract each step (frame) of the animation. What we are interested in is in updating a Sprite, which is a method that sets the next step in the animation.

class Sprite {
    // current step/frame in the animation
    private int cFrame = 0;

    // update code for Sprite class
    public void update(int delta) {
        // some code

        cFrame = getNextFrame();  // this call ensures that the next animation step is set

       // some code
    }
}

That way, all the Sprites on my games get their animation updated (Sprite.update(int)) every frame of the game (every pass on the game loop).

I’m not sure it’s clear from this explanation, so if you think something is obscure just ask, I’d be willing to clarify :slight_smile:

Also, all the code I’ve posted is a previous version of what I do right now. If someone thinks its a bad idea to do it as I do please, tell me! I am learning too, so any advice would be perfect.

I know you’re not using LWJGL, BUUUUUUUUUT. I like the way this example/tutorial shows timing and delta.

Have a read:
http://lwjgl.org/wiki/index.php?title=LWJGL_Basics_4_(Timing)

But do try LWJGL in the future. :slight_smile:

I’ve tried LWJGL, OpenGL, Jme, ogre, not i’m taking some time to make me a 2D rpg.

I have a cycle, perfect rendering, fps, other fun player variables,(cash,GREAT debugging system).
BUUUUUUT, I need a animation stage…
Please do try and give me feedback, i’ve tried multiple ways.

if (keyPressed == right) {
		absX++;
		//Draw the first image
		sprite = new image(#1);
}

if (keyReleased == right) {
		//Than draw the second image.
		sprite = new image(#2);
}

This still doesn’t cut it.

If you need to cycle between multiple images, why don’t you hold all the images in an array and just increase a variable every frame:


//say 0 = standing still, 1-4 are animation
Image[] frames = new Image[5];
int currentFrame = 0;

...

public void update(long delta) {
    if(walking) {
        currentFrame++;
        if(currentFrame == 5)
            currentFrame = 1;
    }
    else
        currentFrame = 0;
    
    ...
}

public void paintComponent(Graphics g) {
    super.paintComponent(g);
    
    g.drawImage(frames[currentFrame],x,y,null);
}

What do you mean by animation stage?

Oh i see, you mean change the image of the character based on the direction it is traveling?

If so, i like to use int facing and have all the images loaded into an array.


BufferedImage imgs = new BufferedImage[5]
//load each image to its own index
int facing = 0; //init to 0

then...

when you test if each key is pressed:

if (leftPressed) {
facing = 1;
velX = -1;
}
etc...

Then you would render your player:
g.drawImage(imgs[facing], x, y, null);

Wowzors, thanks alot guys, that actually helped my problem!.
Much, much appreciated, also very simple.
One problem, if someone can advise me on, if im holding LEFT, and DOWN, it spams error about a “at java.awt.EventDispatchThread.run()/PumpEvents”, is that because i should need to re-edit the code to detect something like this?

if (p.isWalkingRight() && !p.isWalkingDown()) {
walkright…
}

Are you checking for keys pressed down separately?

Maybe post your update method please.

What is the exact stack trace? That class/method is part of the behind-the-scenes AWT EDT thread. Maybe one of your listener methods threw an exception?

It’s launched in the FloorMap.java of mine, used by a method of “time = new Timer(delay, this);”

	public FloorMap() {
		anim = 0;
		p = new Player();
		addKeyListener(new AL());
		setFocusable(true);
		img = mapBack.getImage();
		time = new Timer(50, this);
		time.start();
		loadPics();
	}

Than from there it looks for the action Performed method, than calls cycle();


	public void actionPerformed(ActionEvent e) {
		cycle();
	}

And this is the cycle() method.


	public void cycle() {
		updateFPS();
		randomCash(); //Random cash for the player
		repaint();
		cycles++;
		checkHp(); //If hps < 0 than act
		poison(); //Random player hp/mana drain
		p.update();
			try {
				if (currentFrame == 15) {
					currentFrame = 0;
		        	p.walkingRight = false;
		        	p.walkingLeft = false;
		        	p.walkingDown = false;
		        	p.walkingUp = false;
					System.out.println("PREVENTED ENGINE CRASH (Error is here!)");
					return;
				}
			   		if (p.walkingDown) {
			   			currentFrame++;
			   				if (currentFrame == 4)
			   					currentFrame = 0;
			   		} else if (p.walkingRight) {
			   			currentFrame++;
			   				if (currentFrame == 7)
			   					currentFrame = 4;
			   		} else if (p.walkingUp) {
			   			currentFrame++;
			   				if (currentFrame == 11)
			   					currentFrame = 8;
				   	}  else if (p.walkingLeft) {
			   			currentFrame++;
		   				if (currentFrame == 15)
		   					currentFrame = 12;
			   	} else {
				   		currentFrame = 0;
			   		}
			} catch (ArrayIndexOutOfBoundsException e2) {
				e2.printStackTrace();
			}
	}

If I comment out the (if (currentFrame == 15)) this is the stacktrace;


Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 24
	at server.FloorMap.paint(FloorMap.java:247)
	at javax.swing.JComponent.paintToOffscreen(Unknown Source)
	at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
	at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
	at javax.swing.RepaintManager.paint(Unknown Source)
	at javax.swing.JComponent._paintImmediately(Unknown Source)
	at javax.swing.JComponent.paintImmediately(Unknown Source)
	at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
	at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
	at javax.swing.RepaintManager.seqPaintDirtyRegions(Unknown Source)
	at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(Unknown Source)
	at java.awt.event.InvocationEvent.dispatch(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.run(Unknown Source)

Believing this is caused from to many keys held down “ArrayIndexOutOfBoundsException: 24”, so i simply restart the frameCount, and all the other walkingDirection booleans.

ALSO, one more problem, say if i press LEFT, it will perform all other 3 animations than turn to the left + walk/animate.
How could i rewrite the main loop to detect them singly (tried like 3 ways and sprites wouldn’t even change. :frowning: )

Could you rephrase that? I don’t understand what you mean by “detecting them singly” :clue:

The current system right now is messed up, if LEFT is pressed, it draws the DOWN animation, the RIGHT animation, than the TOP, than the actual method its suppose to handle.

Here’s the current way for this, I really wouldn’t like to keep it as is, right now the only variables i have for telling the position of the player is the absX, absY, and h, basicly h = absY(height).

This just looks like one big ugly loop:


	public void cycle() {
	try {
				if (p.walkingDown) {
			   			currentFrame++;
			   				if (currentFrame == 4)
			   					currentFrame = 0;
			   		} else if (p.walkingRight) {
			   			currentFrame++;
			   				if (currentFrame == 7)
			   					currentFrame = 4;
			   		} else if (p.walkingUp) {
			   			currentFrame++;
			   				if (currentFrame == 11)
			   					currentFrame = 8;
				   	}  else if (p.walkingLeft) {
			   			currentFrame++;
		   				if (currentFrame == 15)
		   					currentFrame = 12;
			   	} else {
				   		currentFrame = 0;
			   		}
	} catch (Exception e1) {
		e1.printStackTrace();
	}

What i would like it to do is look cleaner, and perform/handle more keys at a time, for instance if LEFT + DOWN is pressed, i would like the sprite to look as if it were going South-West at a angle, (absX–, absY–) or vice versa, kind of what i would like.
Hope you can understand, is it possible that you would overlook all my coding if i posted it, (when you could), and you could possibly tell me what to improve/tidy up/catch, right now the FPS ranges from 30-65.

My solution:

Let’s say you have the following tileset:

The order of the frames (per character) is what I want to show. Up, left, right, down.

First, to draw individual frames (choose one):
OPTION 1: Split up the image into an array of BufferedImages. Index 0 is the first frame. This is the easiest one. TIP: BufferedImage.getSubimage(int x, int y, int w, int h)
OPTION 2: Keep the full tileset loaded in memory, and create a method that draws a frame from the image using only a frame index. TIP: Graphics2D.drawImage(…), the one that allows you to draw only parts of an image.

To decide which frame to draw, do this:


public class Character{

    private static final int UP = 0;
    private static final int LEFT = 1;
    private static final int RIGHT = 2;
    private static final int DOWN = 3;

    private BufferedImage[] frames; //OPTION 1
    private TiledImage tileset; //OPTION 2 (You'll have to make the TiledImage class yourself)

    private int x, y; //Position
    private int direction = DOWN; //Facing direction

    private boolean walking = false;
    private int animationFrame = 1;

    public Character(...){
        //Take in relevant data in the constructor, load images, e.t.c.
    }

    public void update(){
        if(walking){
            animationFrame++;
            if(animationFrame == 3){
                animationFrame = 0;
            }
            //Also update position based on direction of movement
        }else{
            animationFrame = 1;
        }
    }

    public void draw(Graphics2D g2d){
        g2d.drawImage(frame[direction * 3 + animationFrame], x, y, null); //OPTION 1
        tileset.drawFrame(g2d, direction * 3 + animationFrame, x, y); //OPTION 2
    }
}

Playing with numbers is fun! =D

[quote]Playing with numbers is fun! =D
[/quote]
Nice! Will have to give this a try tonight.

What I have been doing is simply in your KeyPressed method for Player, set leftPressed to true when left is pressed, rightPressed to true when right is pressed, etc and in KeyReleased set them to false. Then somewhere in your main loop have it check if they’re pressed and have an integer like switch. Every cycle that one is pressed, add one to switch, and when switch is above 25 or so, set the sprite to a different part of the cycle. Do the same thing at 50, 75, 100, etc and at the end of the cycle set it back to 0.

Hope this helps (:

Thank you, i’m about to head out the door at the moment for a dentist appointment, will try this when i get back ^_^.