Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (539)
Games in Android Showcase (132)
games submitted by our members
Games in WIP (603)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  [Java 2D Character Animation]  (Read 6246 times)
0 Members and 1 Guest are viewing this topic.
Offline GabrielBailey74
« Posted 2012-01-08 07:12:27 »

Hello guys, this is my FIRST post on these forums!, just simply googled java programming forums and hey, here I am Smiley, 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:
1  
2  
3  
4  
5  
6  
        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)
1  
2  
3  
4  
5  
   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.

Offline jammas615

Junior Devvie


Projects: 1



« Reply #1 - Posted 2012-01-08 09:39:04 »

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.

Offline GabrielBailey74
« Reply #2 - Posted 2012-01-08 09:55:52 »

Do you have any idea about how i would go in doing that? Shocked
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?

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline yuma

Junior Devvie


Medals: 2
Projects: 1


Monkeys are listening


« Reply #3 - Posted 2012-01-08 12:07:23 »

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:

1  
2  
3  
4  
5  
6  
7  
8  
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.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
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 :-)

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.

Offline jammas615

Junior Devvie


Projects: 1



« Reply #4 - Posted 2012-01-08 12:35:04 »

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_%28Timing%29

But do try LWJGL in the future. Smiley

Offline GabrielBailey74
« Reply #5 - Posted 2012-01-08 13:57:11 »

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.


1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
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.

Offline ra4king

JGO Kernel


Medals: 356
Projects: 3
Exp: 5 years


I'm the King!


« Reply #6 - Posted 2012-01-08 21:13:04 »

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:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
//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);
}

Offline jammas615

Junior Devvie


Projects: 1



« Reply #7 - Posted 2012-01-09 00:08:52 »

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.
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
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);

Offline GabrielBailey74
« Reply #8 - Posted 2012-01-09 02:07:14 »

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..
}

Offline jammas615

Junior Devvie


Projects: 1



« Reply #9 - Posted 2012-01-09 02:57:48 »

Are you checking for keys pressed down separately?

Maybe post your update method please.

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline ra4king

JGO Kernel


Medals: 356
Projects: 3
Exp: 5 years


I'm the King!


« Reply #10 - Posted 2012-01-09 03:29:07 »

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?

Offline GabrielBailey74
« Reply #11 - Posted 2012-01-09 03:30:10 »

It's launched in the FloorMap.java of mine, used by a method of "time = new Timer(delay, this);"
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
   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();

1  
2  
3  
   public void actionPerformed(ActionEvent e) {
      cycle();
   }


And this is the cycle() method.
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
   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;
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
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. Sad )

Offline ra4king

JGO Kernel


Medals: 356
Projects: 3
Exp: 5 years


I'm the King!


« Reply #12 - Posted 2012-01-09 05:20:39 »

Could you rephrase that? I don't understand what you mean by "detecting them singly" Clueless

Offline GabrielBailey74
« Reply #13 - Posted 2012-01-09 05:43:56 »

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:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
   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.

Offline theagentd

« JGO Bitwise Duke »


Medals: 366
Projects: 2
Exp: 8 years



« Reply #14 - Posted 2012-01-09 06:48:44 »

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:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
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

Myomyomyo.
Offline wookoouk

Senior Newbie





« Reply #15 - Posted 2012-01-09 10:29:31 »

Quote
Playing with numbers is fun! =D

Nice! Will have to give this a try tonight.
Offline StonePickaxes

JGO Coder


Medals: 4
Projects: 2


Nathan Kramber


« Reply #16 - Posted 2012-01-10 14:06:40 »

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 (:

Check out my website!
Offline GabrielBailey74
« Reply #17 - Posted 2012-01-10 18:14:36 »

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

Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

rwatson462 (33 views)
2014-12-15 09:26:44

Mr.CodeIt (23 views)
2014-12-14 19:50:38

BurntPizza (51 views)
2014-12-09 22:41:13

BurntPizza (84 views)
2014-12-08 04:46:31

JscottyBieshaar (45 views)
2014-12-05 12:39:02

SHC (59 views)
2014-12-03 16:27:13

CopyableCougar4 (60 views)
2014-11-29 21:32:03

toopeicgaming1999 (123 views)
2014-11-26 15:22:04

toopeicgaming1999 (114 views)
2014-11-26 15:20:36

toopeicgaming1999 (32 views)
2014-11-26 15:20:08
Resources for WIP games
by kpars
2014-12-18 10:26:14

Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!