Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (472)
Games in Android Showcase (105)
games submitted by our members
Games in WIP (524)
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  
  2D Walking Animation (edited - different approach)  (Read 3780 times)
0 Members and 1 Guest are viewing this topic.
Offline Mads

JGO Ninja


Medals: 26
Projects: 3
Exp: 6 years


One for all!


« Posted 2011-01-28 18:00:13 »

Old post:
Quote
I have a problem. I can't get this to animate right :/
Spritesheet:


My game is a rough pokemon clone. The world is tiled.
 The player movement is smooth and great, but the animation is not working and I can't think of a way to implement it correctly.
Basicly, this functionality is my goal:
When just pressing once (moving one tile), the animation should be mid-layer on the spritesheet, downer layer, and when hitting the right position still (upper layer).
When holding down it should be mid-layer, upper layer, downer-layer, upper layer, and repeating (in order to get a nice walking animation).

I've tried my best here (a peice of my player-class):
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  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
public void update(long delta) {
        if (appearenceUpdate) {
            image = ImagesLoader.character[moveDir - 1][imageY];
            appearenceUpdate = false;
        }
        if (animUpdate) {
           switch (lastY) {
               case 1:
                   lastY = 2;
                   break;
               case 2:
                   lastY = 1;
                   break;
           }
           switch (imageY) {
               case 0:
                   imageY = lastY;
                   break;
               case 1:
                   imageY = 0;
                   break;
               case 2:
                   imageY = 0;
                   break;
           }
            image = ImagesLoader.character[moveDir - 1][imageY];
            animUpdate = false;
        }
       

        // Position logic
       if (isMoving) {
            if (map.targX != map.mapStartX
                    || map.targY != map.mapStartY) {
                long now = System.nanoTime();
                timeSinceLocUpdate += (long) (now - delta); //* 1000000;
               if (timeSinceLocUpdate > locFPS) { // Move 1 px
                   if (animPointX == map.mapStartX && animPointY == map.mapStartY) {
                        animUpdate = true;
                    }
                    move(moveDir);
                    timeSinceLocUpdate = 0;
                }          
            } else if (isKeyDown) {
                coordX = targX;
                coordY = targY;
                calcNewCoords(moveDir);
                animUpdate = true;
            } else {
                coordX = targX;
                coordY = targY;
                //appearenceUpdate = true;
               //imageY = 0;
               isMoving = false;
                gpTop.blockInput = false;
            }
        } else {
            //imageY = 0;
           gpTop.blockInput = false;
        }
    }

    public void calcNewCoords(int dir) {
        switch (dir) {
            case 1:
                targY = coordY - 1;
                targX = coordX;
                if (map.checkObstacle(targX, targY)) {
                    map.targX = map.mapStartX;
                    map.targY = map.mapStartY + map.tileHeight;
                    animPointX = map.targX;
                    animPointY = map.targY - (map.tileHeight / 2);
                } else {
                    targX = coordX;
                    targY = coordY;
                }
                break;
            case 2:
                targX = coordX + 1;
                targY = coordY;
                if (map.checkObstacle(targX, targY)) {
                    map.targX = map.mapStartX - map.tileWidth;
                    map.targY = map.mapStartY;
                    animPointY = map.targY;
                    animPointX = map.targX + (map.tileWidth / 2);
                } else {
                    targX = coordX;
                    targY = coordY;
                }
                break;
            case 3:
                targY = coordY + 1;
                targX = coordX;
                if (map.checkObstacle(targX, targY)) {
                    map.targY = map.mapStartY - map.tileHeight;
                    map.targX = map.mapStartX;
                    animPointX = map.targX;
                    animPointY = map.targY + (map.tileHeight / 2);
                } else {
                    targX = coordX;
                    targY = coordY;
                }
                break;
            case 4:
                targX = coordX - 1;
                targY = coordY;
                if (map.checkObstacle(targX, targY)) {
                    map.targX = map.mapStartX + map.tileWidth;
                    map.targY = map.mapStartY;
                    animPointY = map.targY;
                    animPointX = map.targX - (map.tileWidth / 2);
                } else {
                    targX = coordX;
                    targY = coordY;
                }
                break;
        }
    }


In player, targX and -Y is the coords to where my player is going.
map.targX and -Y is the pixel coords to where the map should stop.
animPointX and -Y is the pixel location of where the player-image should change state (upper-layer to downer-layer or vice-versa).
The appearenceUpdate boolean is a flag that is set when a movement-key is pressed. The animUpdate boolean, is a flag that is set when the image should change due to animation.

My ImagesLoader loads the spritesheet and slices it, making it available through coordinates via. a bufferedimage[][] (x, and y).

EDIT:
I'm beginning to think that the calcNewCoords methods does not calculate the animPoints correctly, even though it seems to me that they are  Sad

EDIT 2:
Am I trying to do this the wrong way?  Undecided

Here is a video of the current functionality (just uploaded so it might be processing...):
http://www.youtube.com/watch?v=cViA0iTZvSo

..and here is a video of the functionality I want (just in case..):
http://www.youtube.com/watch?v=yYHuitGE54U&playnext=1&list=PL3CE5F96EF3D7C2B5

Oh, and the keylistener:
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  
private void processKey(KeyEvent e) {
        int keyCode = e.getKeyCode();
        player.appearenceUpdate = true;
        if (!blockInput) {
            if (keyCode == KeyEvent.VK_UP) {
                player.moveDir = 1;
                player.isKeyDown = true;
                blockInput = true;
                player.calcNewCoords(player.moveDir);
                player.isMoving = true;
            }
            if (keyCode == KeyEvent.VK_RIGHT) {
                player.moveDir = 2;
                player.isKeyDown = true;
                blockInput = true;
                player.calcNewCoords(player.moveDir);
                player.isMoving = true;
            }
            if (keyCode == KeyEvent.VK_DOWN) {
                player.moveDir = 3;
                player.isKeyDown = true;
                blockInput = true;
                player.calcNewCoords(player.moveDir);
                player.isMoving = true;
            }
            if (keyCode == KeyEvent.VK_LEFT) {
                player.moveDir = 4;
                player.isKeyDown = true;
                blockInput = true;
                player.calcNewCoords(player.moveDir);
                player.isMoving = true;
            }
            if (keyCode == KeyEvent.VK_X) {
                player.locFPS = 1000000 / 100;
            }
        }
    }  // end of processKey()


Any ideas?  Lips Sealed

Since that didn't work out too well, I tried to just play an animation of three images (y coordinate: 2,0,1), while walking.
This is what I got:
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  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
private long timeSinceLocUpdate;
    private long timeSinceAnimUpdate;
    public long locFPS = 1000000 / 9;
    public long animFPS = (locFPS * 16) / 3;

    public int animation[] = {1,0,2};
    private int counter = 0;

    public void update(long delta) {  
        long now = System.nanoTime();
        if (isMoving) {
            timeSinceAnimUpdate += (long) (now - delta);
            if (timeSinceAnimUpdate > animFPS) { // A third of the time moving has past
               counter++;
                if (2 < counter) {
                    counter = 2;
                }
                timeSinceAnimUpdate = 0;
            }
        } else {
            counter = 0;
        }

        // Position logic
       if (isMoving) {
            if (map.targX != map.mapStartX
                    || map.targY != map.mapStartY) {
                timeSinceLocUpdate += (long) (now - delta); //* 1000000;
               if (timeSinceLocUpdate > locFPS) { // Move 1 px
                   move(moveDir);
                    timeSinceLocUpdate = 0;
                }          
            } else if (isKeyDown) {
                coordX = targX;
                coordY = targY;
                calcNewCoords(moveDir);
            } else {
                coordX = targX;
                coordY = targY;
                appearenceUpdate = true;
                isMoving = false;
                gpTop.blockInput = false;
            }
        } else {
        }
    }

    public void draw(Graphics g) {
        x = (map.PWIDTH / 2) - (width / 2);
        y = (map.PHEIGHT / 2) - (height / 2);
        g.setColor(Color.ORANGE);
        if (isMoving) {
            g.drawImage(ImagesLoader.character[moveDir - 1][animation[counter]], x, y, null);
        } else {
            g.drawImage(ImagesLoader.character[moveDir - 1][0], x, y, null);
        }
    }


calcNewCoords now only handles location targets, and the keylistener now just sets the isMoving boolean, and the moveDir (the direction the sprite is facing).

However, this doesn't work right: The animation isn't "smooth". The last frame (animation[2]) is usually a lot longer than the other two.
I think this implementation of animating the walking is easier to manage, and the problem is smaller.
I think what's happening, is that the animation-counter quickly reaches 2, and stays there for the two last frames. To me, it looks like it should not.

Offline Mads

JGO Ninja


Medals: 26
Projects: 3
Exp: 6 years


One for all!


« Reply #1 - Posted 2011-01-29 13:00:24 »

I give up Sad How should this be implemented? I'm using Slick, if that could help my problem in any way?  Undecided

EDIT: I cheaphacked it..  Huh

Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11


Game Engineer


« Reply #2 - Posted 2011-01-30 02:14:45 »

Yeah, it seems like you're thinking about it the wrong way. Try to go more object oriented. In reality, you've got three separate things:
- The sprite sheet and the logic of which frame is where
- The animation, which knows which frames get swapped after the others and how long the delay is between frames
- The game logic, which decides when to show which animation

Usually for me this translates to my Entity class having an AnimationSet. An AnimationSet is a HashMap of Animation's with a String as a key, so I can say entity.setAnimation("WalkUp") and it will start playing that one. The AnimationSet has logic for priorities and whatnot so that certain Animation's automatically play by default (like an Idle animation) and others can't be interrupted (like a Death animation). Each Animation has an array of String's that reference Sprites stored in memory, so I can just draw a different image depending on what the current frame is. You seem to understand how a Sprite sheet / atlas works, so I won't bother explaining that part.

Does all that make sense?

See my work:
OTC Software
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Mads

JGO Ninja


Medals: 26
Projects: 3
Exp: 6 years


One for all!


« Reply #3 - Posted 2011-01-30 10:46:15 »

..so I can just draw a different image depending on what the current frame is.

About here I jumped off.. I'm using slick now, so basicly I can have my enities have a hashmap of animations (as in the objects in Slick), and play them according to the state of the entity (walking different directions and dying)?

I'm not sure if Slick lets me move it around once started.. Else I'll have to make it myself.. I think I know how to go about this, except for one thing: How do I know when to update the picture in the animation?
Should I just let it play to the end? If so, what about holding down the key for continous walking?
Replay, to the end?

Offline N15M0

Senior Newbie





« Reply #4 - Posted 2011-01-30 12:32:30 »

Hi Mads,

It seems like we are working on a similar sort of thing.

I had a look at Slick, but decided to only use Java2D instead of any extra libraries. My animations are controlled with 2 integers for the direction which the character is facing(dirx, diry, where -1, 0 and 1 are values). This will help determine which image set to render.

My images are seperated instead of being on an image set, but there will just be a separate bit of programming for you to do. Whenever the actionListioner() is called by your timer, another method will alter another variable which changes the image currently being displayed. Here is a code representation, please keep in mind this only represents a single direction:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
Image[] imgArr = new Image[3];//An array of 3 images, the images for your animation.
int currentImage=0;//An integer representing the current image.

public void changeImg()//A method to change the image to be displayed
{
currentImage++;//Increase the current image variable

if(currentImage==3)//If the current image is '3', which cant be used to get the image later, set it to 0.
currentImage=0;
}

public Image getImage()
{
return imgArr[currentImage];
}


This way, you can change the image in the paint() method of your program. Hope this helps a bit! Smiley
Offline N15M0

Senior Newbie





« Reply #5 - Posted 2011-01-30 12:36:12 »

Oh, and one other thing, it may be useful to use the 'Sprite' class found in the tools directory of your Slick download. It represents a single sprite in your program, but you could make an AnimatedSprite class which extends Sprite and impliments the above code or something somehow... Just an idea
Offline Mads

JGO Ninja


Medals: 26
Projects: 3
Exp: 6 years


One for all!


« Reply #6 - Posted 2011-01-30 19:44:48 »

Hi Mads,

It seems like we are working on a similar sort of thing.

I had a look at Slick, but decided to only use Java2D instead of any extra libraries. My animations are controlled with 2 integers for the direction which the character is facing(dirx, diry, where -1, 0 and 1 are values). This will help determine which image set to render.

My images are seperated instead of being on an image set, but there will just be a separate bit of programming for you to do. Whenever the actionListioner() is called by your timer, another method will alter another variable which changes the image currently being displayed. Here is a code representation, please keep in mind this only represents a single direction:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
Image[] imgArr = new Image[3];//An array of 3 images, the images for your animation.
int currentImage=0;//An integer representing the current image.

public void changeImg()//A method to change the image to be displayed
{
currentImage++;//Increase the current image variable

if(currentImage==3)//If the current image is '3', which cant be used to get the image later, set it to 0.
currentImage=0;
}

public Image getImage()
{
return imgArr[currentImage];
}


This way, you can change the image in the paint() method of your program. Hope this helps a bit! Smiley

Hi N15MO  Cheesy

I actually used that technique, but for me it played too fast over the first image, and then coughed when reaching the end before planned. I also had an event where the sprite reached the position, where I would set the image back to the "standing" image. A combination of that worked really bad.
However, I think just setting the "standing" image, when the animation is done will fix that. The problems are just going to fall on me when I reach a point, where I'd like to implement NPC's that are able to walk. I also have the pseudocode, but I doubt it'll actually work  Lips Sealed
Oh, and do you mind explaining why you use two integers, for the direction?
I like to just have one integer/short/byte going from 1 through 4. North, east, south, and west.


Just out of interrest, can I see what you've done so far?  Tongue

Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11


Game Engineer


« Reply #7 - Posted 2011-01-31 04:09:57 »

I'm not sure how Slick works, but you update the animation by calling tick() on it every timestep. That will then increment a counter, and when it reaches the delay for that frame it moves on to the next one.

See my work:
OTC Software
Offline N15M0

Senior Newbie





« Reply #8 - Posted 2011-02-01 18:58:47 »

Hi Mads Smiley

I see youre predicament... Hmmmm i really havent done much to be able to help u with anything, but when i do i will post it here and show u. Because i am still pretty new to this forum, i cant past any links to websites, but please go ahead and type "pacman java 2d game tutorial" in Google and look at the one from Zetcode. It is what i am basing my animation around, also maybe look at their tutorial on animation itself and moving sprites, i think there will be valuable information in there to help u Smiley

Concerning the two integer variables, becasue its 2d we're working in, u may want a character to to so something really strange like strafe or side step, and u cannot account for that with one variable... but if you only intend to have the character going in the usual up/down/left/right sort of fashion, it can suffice too Smiley when i have some spare time this week, ill take a look at your code and maybe help out a bit if i can Smiley

I plan to have my project finished in the next 2/3 weeks before university starts
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.

CopyableCougar4 (8 views)
2014-07-10 02:26:14

CopyableCougar4 (22 views)
2014-07-09 02:55:38

Code Mage (22 views)
2014-07-08 23:57:00

Code Mage (7 views)
2014-07-08 23:49:08

AppleSauce (19 views)
2014-07-08 19:25:32

CopyableCougar4 (21 views)
2014-07-06 01:51:26

ipe369 (25 views)
2014-07-05 14:18:25

vastrolorde (35 views)
2014-07-04 18:45:44

theagentd (53 views)
2014-07-02 22:19:37

theagentd (50 views)
2014-07-02 22:17:51
HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54

HotSpot Options
by Roquen
2014-05-06 15:03:10

Escape Analysis
by Roquen
2014-04-29 22:16:43

Experimental Toys
by Roquen
2014-04-28 13:24:22
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!