Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (107)
games submitted by our members
Games in WIP (536)
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  
  Properly implementing animation cycles  (Read 1896 times)
0 Members and 1 Guest are viewing this topic.
Offline Wolfner

Senior Newbie





« Posted 2011-06-02 12:08:09 »

Hi there,

lately I've been programming again and there is something i really wonder about:

How can i properly implement animations like swinging a sword arm or the like?
(I'm talking about 2D animations here)

My former approach to this went something like this:
* KeyEvent for attack is fired
* Boolean for attack animation is set true
* Set a byte coordinating the animation to 1

Within the paint() method:
* As long as the boolean is true
   - Draw a certain part of the animation according to the coordination byte
   - increase the coordination byte
   - if the byte has reached a certain height (depending on how many single pictures i want to draw for this animation) set the boolean for the animation to false and the byte to 0

Obviously there are two major problems with this approach:
1) Every animation is completely hard coded. You definitely could pack all animations in separate class files but I have the feeling this problem could be fixed much more efficiently.
2) Every animation will run with different speed on different machines due to the fact that for example faster PCs process more paint()-methods in less time.

What are some other/better approaches to implementing animation cycles?

Best regards,
Wolfner

[IMG]http://www7.pic-upload.de/19.06.11/f6qp8oiqop8s.gif
Offline cylab

JGO Ninja


Medals: 38



« Reply #1 - Posted 2011-06-02 15:30:45 »

Actually this is more or less how you do it!

1) Every animation is completely hard coded. You definitely could pack all animations in separate class files but I have the feeling this problem could be fixed much more efficiently.

This smells like you don't utilize the object orientated purpose of a class file. Usually you have ONE class that handles an animation and just instantiate objects of this class with different constructor parameters.

2) Every animation will run with different speed on different machines due to the fact that for example faster PCs process more paint()-methods in less time.

You need to make a gameLoop with constant paint intervals here ("fixed time step" rendering), so you always have the same amount of paint()-calls per second (usually you speak of frames per second or fps here), regardless of PC speed. (There is another approach called "variable time step", but it is slightly more complex to implement)


Mathias - I Know What [you] Did Last Summer!
Offline Wolfner

Senior Newbie





« Reply #2 - Posted 2011-06-02 16:06:50 »

Thanks a lot!

While we are speaking of gameLoops and such:

I'm used to writing my Java applications according to the MVC pattern and I was wondering if there are equivalent patterns for organising your program logic when it comes to game developement.

[IMG]http://www7.pic-upload.de/19.06.11/f6qp8oiqop8s.gif
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline ra4king

JGO Kernel


Medals: 337
Projects: 2
Exp: 5 years


I'm the King!


« Reply #3 - Posted 2011-06-02 18:30:08 »

Check out my implementation of an Animation class.

Offline Z-Man
« Reply #4 - Posted 2011-06-02 19:38:42 »

This is unrelated to the OP's question but it's a bit small to start a new thread over. I was looking at your Animation class ra4king and I came across this, could you tell me what it does? Specifically the middle part "? null :" I have never seen it before.
[CODE]return frames.size() == 0 ? null : frames.get(frameIndex).i;[/CODE]

EDIT: To me it looks like it checks to make sure that the ArrayList isn't empty, if it is empty return null, otherwise return the current frame. Is that correct? I'm just not familiar with this kind of syntax in a return statement.
Offline cylab

JGO Ninja


Medals: 38



« Reply #5 - Posted 2011-06-02 20:10:39 »

It's called a ternary operator, see http://en.wikipedia.org/wiki/%3F:

Mathias - I Know What [you] Did Last Summer!
Offline ra4king

JGO Kernel


Medals: 337
Projects: 2
Exp: 5 years


I'm the King!


« Reply #6 - Posted 2011-06-02 20:13:48 »

Unrelated? It seems like this is what he needs. Instead of incrementing a byte index in the paint method, he needs to call the update method in the Animation class each tick of his game loop and just get the current frame of the animation in the paint method.

And that is called a ternary operator. It is basically a simplified if-else statement, but it returns a value:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
return frames.size() == 0 ? null : frames.get(frameIndex).i;

//that is the same thing as:

if(frames.size() == 0)
    return null;
else
    return frames.get(frameIndex).i;

//another example to find the maximum value:
int max = value1 > value2 ? value1 : value2;

//is the same thing as
int max;
if(value1 > value2)
   max = value1;
else
   max = value2;

Offline Z-Man
« Reply #7 - Posted 2011-06-02 20:25:34 »

Ah thanks for explaning ra4king, and thanks for the link cylab.
Offline loom_weaver

JGO Coder


Medals: 17



« Reply #8 - Posted 2011-06-02 20:27:09 »

Wolfner, a few of questions about your game:

1. Is it turn-based?
2. Do you use active or passive rendering?
3. When is your game state updated?  E.g. consider a death animation.  Does the monster die, the game state is updated, and then the animation is played?  Or do you launch the animation, and when the monster hits the ground, you update the game state?
Offline Wolfner

Senior Newbie





« Reply #9 - Posted 2011-06-03 00:46:51 »

I actually wanted to start out small and make one of those little shooters where you are looking at a landscape and enemies just pop up somewhere on the screen.

Considering this and the fact that every enemy just takes one shot I guess it'll be the best to update the gamestate right after the enemy's death. Especially when you think about the typical situation in such games: You have like one second left (assuming that the time is limited) and you want to get the points of that last guy you only just hit.
If I would update the data model (i hope this is what you mean with the gamestate) after the animation this might lead to some problems. For example I'm thinking of hits that are not minded in the players score (assuming again that every kill rewards you with a certain amount of points).

I'm not sure what you mean with active/passive rendering though.

[IMG]http://www7.pic-upload.de/19.06.11/f6qp8oiqop8s.gif
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline ra4king

JGO Kernel


Medals: 337
Projects: 2
Exp: 5 years


I'm the King!


« Reply #10 - Posted 2011-06-03 02:11:35 »

Active rendering is when you explicitly call the drawing code every tick. This method is preferred because it guarantees screen updates. Canvas + BufferStrategy are the typical tools when doing active rendering.

Passive rendering is when you call a method like repaint() and then wait for the EventQueue to call the paint() method. The problems with this is each repaint is not immediate and the EDT (Event Dispatching Thread) tends to group similar events together if they occur too closely to one another.

Offline Wolfner

Senior Newbie





« Reply #11 - Posted 2011-06-03 11:58:02 »

I see. Well, going by that I would say I always used passive rendering.
As I mentioned somewhere above I'm still missing the right pattern for organising my code. I guess that's a highly individual thing.

[IMG]http://www7.pic-upload.de/19.06.11/f6qp8oiqop8s.gif
Offline cylab

JGO Ninja


Medals: 38



« Reply #12 - Posted 2011-06-03 14:03:44 »

If you want to get something done, make it quick and dirty and only refactor it to something more "pattern-like" if you find it will really help you... well, getting it done.

Most people comming from a more structured multiperson work environment tend to do software design and want library like reusable code. This won't get you anywhere in a oneperson hobby project.

Mathias - I Know What [you] Did Last Summer!
Offline loom_weaver

JGO Coder


Medals: 17



« Reply #13 - Posted 2011-06-03 15:33:46 »

I see. Well, going by that I would say I always used passive rendering.

Okay good to know.  I'm trying to understand the whole picture.  One last question: how do you advance your game loop and animation loop?  Do you use a timer?
Offline Wolfner

Senior Newbie





« Reply #14 - Posted 2011-06-03 16:43:31 »

At the moment I use a thread which sleeps for about 40 miliseconds and then repaints/updates stuff.

[IMG]http://www7.pic-upload.de/19.06.11/f6qp8oiqop8s.gif
Offline loom_weaver

JGO Coder


Medals: 17



« Reply #15 - Posted 2011-06-03 17:32:35 »

Okay, this is what I have done and might work nicely in your situation.  I use passive rendering as well with a Timer that updates stuff about 20 times per second.

First I have a class that represents an active/playing animation.  Note the code snippets are pseuo-code:
1  
2  
3  
4  
5  
abstract class Animation {
    Image getImageToDraw();  // get stuff to draw.  Called from paint().
   boolean isComplete();  // return true if animation is completed
   boolean advance();  // potentially advance the animation.  Called every timer tick.  Return true if animation has advanced and repaint is required.
}


Then in your main Panel you store all running animations:
1  
List[Animation] animations;


Your timer tick might be (assuming the callback is in your main Panel class):
1  
2  
3  
4  
5  
6  
7  
8  
9  
public void callback() {
    remove all animations where anim.isComplete() == true

    for (Animation anim in animations) {
        if (anim.advance()) {
            repaint();
        }
    }
}


And paint() appears as such:
1  
2  
3  
4  
5  
6  
7  
public void paint(Graphics g) {
    super(g);

    for (Animation anim in animations) {
        g.draw(anim.getImageToDraw());
    }
}



Finally you need to create an implementation of Animation.  Let's assume you have a death animation that consists of 8 images and you want it to play over the course of 2 seconds.
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  
class DeathAnimation extends Animation {
    private boolean isDone = false;
    private long start_ms;
    private List[Image] images;
    private int i = 0;

    DeathAnimation() {
        initialize all your images
        start_ms = System.currentTimeMillis();
    }

    Image getImageToDraw() {
        return images[i];
    }

    boolean isComplete() {
        return isDone;
    }

    boolean advance() {
        long elapsed_ms = System.currentTimeMillis() - start_ms;

        int calcI = elapsed_ms / 250;  // advance animation 4 frames per sec

        if (calcI >= 8) {
            calcI = 7;
            isDone = true;
        }

        if (i != calcI) {
            i = calcI;
            return true;
        }

        return false;  // no repaint needed
   }
}


So basically, your code maintains a list of running animations.  Each game tick (40 msec) you iterate through them and see if you need to advance the animation.  The advance also determines if the animation is complete.

The above code will encapsulate your 'coordinate byte' within the Animation class itself.  It also properly advances the animation at a desired frame-rate independent of the machine speed.

If you want to spawn a new animation all your need to do is instantiate it and add it to the list e.g. animations.add(new DeathAnimation());

This has worked well for me in that my animations are independent of my main Panel class and I've found it really easy to add new ones.  The above code is pretty rough and you may need to adjust it a lot for your game but I hope it gives you the general idea.
Offline Wolfner

Senior Newbie





« Reply #16 - Posted 2011-06-03 20:20:54 »

Wow thanks! Smiley

I'll insert this into my project as soon as possible and let you know how it worked out!

[IMG]http://www7.pic-upload.de/19.06.11/f6qp8oiqop8s.gif
Offline ra4king

JGO Kernel


Medals: 337
Projects: 2
Exp: 5 years


I'm the King!


« Reply #17 - Posted 2011-06-04 00:19:02 »

If you eventually use active rendering and have a deltaTime'd update loop, the Animation class I gave you will help you a lot.
If you need help with good game loops, just ask Smiley

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.

Riven (12 views)
2014-07-29 18:09:19

Riven (8 views)
2014-07-29 18:08:52

Dwinin (9 views)
2014-07-29 10:59:34

E.R. Fleming (25 views)
2014-07-29 03:07:13

E.R. Fleming (10 views)
2014-07-29 03:06:25

pw (39 views)
2014-07-24 01:59:36

Riven (39 views)
2014-07-23 21:16:32

Riven (27 views)
2014-07-23 21:07:15

Riven (28 views)
2014-07-23 20:56:16

ctomni231 (59 views)
2014-07-18 06:55:21
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!