Jump to content
  • Advertisement
Sign in to follow this  
zuhane

The best way to manage sprite sheet animations?

This topic is 1152 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello again!

 

Given my previous success with this forum, I thought I'd ask for your opinions once again! I've been all over Google, but I haven't

really found anything that helps with something this specific, I suppose.

 

I currently have an animation class within my game. All objects that have any screen time (players, monsters, props, bullets, etc)

basically keep an instance of this class. This means that if an object's state changes (ie. dying, jumping, attacking, etc), the animation

can follow over the top of this entity and then change on demand, depending on what it needs to do.

 

Now, all of these entities inherit a single base class. This class has an abstract method inside that all child class must implement

called MakeChangesToAnimation() which is called in the base update. All child classes therefore have a method in which they can

tweak the animation depending on the object's current state. For example, if the character attacks, you could have a few lines of

code saying "if attackType == Attacks.Uppercut -> animation.sheetPosX = 0, animation.sheetPosX = 2, animation.frameSpeed = 5" or something like that.

This seems to work fine, but does lead to some slightly ugly code, as it becomes a messy mixture of nested if statements.

 

Also, the player has about 30 different animations, and the code to make sure the correct strips of the sprite sheet play is just this

awful jungle of nested if statements and repeated code. Is this the best way to go about animation, or would you recommend something

a bit more graceful?

Edited by zuhane

Share this post


Link to post
Share on other sites
Advertisement
I can't really visualize how you end up with nested if statements, but would it help if you bundle the animation details into a separate class?
For each animation you make an object that sets up the animation.

Then build a mapping from attack_type to animation (by an array, a block of code, or attaching the animation to the attack_type itself).
Code then becomes something like GetAnimation(attack_type)->StartAnimation() or so.

Share this post


Link to post
Share on other sites

Just adding..

I find the logic for animation switching can become quite complex depending on the sophistication of character interactions. I actually rewrote my animation class to be as simple as possible trying to minimize conditional switching as you mentioned.

Something like:

 

Character[Ryu].PlayAnimation(UpperCut, facing, [...optional parameters here...] );      // optionals would be like conditional play-speed(ie: underwater), etc..

 

(Depending on character - all my logic would be kept in a player or character class for determining animations)

Where PlayAnimation uses enumerated animation UpperCut, which is assigned the animation index. The Player plays a strip of animation from the sprite sheet based on predefined speed, position and so on which are also loaded from a file corresponding to the sheet. If you use a sheet packer, you may need to set up an editor to adjust the extraction boxes for each image you would normally use in an animation strip [otherwise you could even simply write the strip info into a text file or into header]. Also you could have it produce test play-back of the selected animation strip you're working on and provide additional information to save to file such as speed (or even frame timing for particular frames if you wanted).

 

It may be handy to also map out on paper - different conditions in which animations can or can't be triggered. ie: different animation triggered when ducking or jumping or running or idle. And then quickly switching animations to adapt to new user input. This is where it becomes very difficult to avoid complex if-then stuff.

Share this post


Link to post
Share on other sites

Hmmmm....

 

The problem with preset animations is that they need to be able to change instantly. Some animations need to be cut off, while others shouldn't

allow for anything to interrupt them. My nested if statements are there because there are so many possible positions for the character to be in.

 

The current player can run, walk, crouch, roll, wall slide, slide, wall roll, etc. He also has different weapons and status effects which can change his

current animation, so there's all these conflicting variables. I do, however, keep all the animation stuff in its own method, so there aren't animation

changes all over each class, as that would cause mass confusion.

 

Are you essentially saying that I should map an ID to each animation, then just do something like call animation.Play(ID)?

 

EDIT: renman29, I think you pretty much understand what my problem is! My animation class itself is rather cohesive and takes

care of all the animation stuff, but it's the actual logic telling the animations WHEN to switch I'm having problems with. It

actually works fine and doesn't glitch for me, but it's a right tangled mess of nested ifs!

Edited by zuhane

Share this post


Link to post
Share on other sites


The problem with preset animations is that they need to be able to change instantly. Some animations need to be cut off, while others shouldn't
allow for anything to interrupt them. My nested if statements are there because there are so many possible positions for the character to be in.
 
The current player can run, walk, crouch, roll, wall slide, slide, wall roll, etc. He also has different weapons and status effects which can change his
current animation, so there's all these conflicting variables. I do, however, keep all the animation stuff in its own method, so there aren't animation
changes all over each class, as that would cause mass confusion.
 
Are you essentially saying that I should map an ID to each animation, then just do something like call animation.Play(ID)?

Essentially yes. In detail it may look like so:

 

Things like "walking", "running", "holding weapon", etc. belong to the behavior state of the character. The player controller (in case of PC) or AI (in case of NPC) decides to eventually change the state, considering the current state, situation, and demands. Here may e.g. "want to jump" (demand) be suppressed due to "currently in air" (state). As can be seen, part of the state can be driven by external sub-systems like collision or even the animation system (e.g. an animation track that is bound to a state variable).

 

For animation playback then look at the current behavior state and map it to one of the animation clips. If it is the same clip as before then continue it, otherwise blend / switch to the new one. However, the playback stores which clip is played and where the playhead currently is. This means that a specific animation frame in a specific clip is picked. Its descriptive data (the "data driven approach" already mentioned in above posts) is used to determine the image frame and belonging offset (from virtual origin to frame origin) and size. These things are set into corresponding slots of the game object. Because the animation frames can be understood as keyframes on a timeline, the variable values associated with the frames can be understood as animation value tracks. Notice please that the playback essentially copies values from the tracks into bound slots, not necessarily knowing for what exact purpose.

 

Later then the renderer looks at the corresponding slots for the offset, size and frame, and performs rendering of exactly this one set-up.

 

In the above solution the sub-systems player control / AI, animation, and rendering are not aware of each other. They communicate indirectly by reading and writing a couple of common variables.

Share this post


Link to post
Share on other sites
 

EDIT: renman29, I think you pretty much understand what my problem is! My animation class itself is rather cohesive and takes
care of all the animation stuff, but it's the actual logic telling the animations WHEN to switch I'm having problems with. It
actually works fine and doesn't glitch for me, but it's a right tangled mess of nested ifs!


Can't you put that into the animation object too?
It is supposed to know everything of a single animation, not only startup, but also switch to another animation.


I have also been pondering whether a state machine for the character state and/or animation state would be useful.
It would allow you to express what options to switch exist (by transitions between states). Since states and animations are probably tightly coupled, you could also code switching between animations in a state transition.

Share this post


Link to post
Share on other sites

I'm still kinda in that twisted nest of if-then boat myself. It works but it becomes quite complex with all the conditions that can exist.

The tricky thing is getting it to decide what portions of animations to select under a wide variety of conditions that will result in legal smooth motion with so many possible outcomes that don't make sense in some situations -- and still make the character reactions look quick, responsive, and animate fluidly.

For example - a tiny sample:

case HEROSTATE.blablabla:

......

...

if (((isJumping == false) && (slow_fall)) || (inWater && previous_jump_pressed == false)) //if not already jumping and didn't just press jump in previous loop:
{
    doubleJumping = false;
    if (jump_pressed) // more logic elsewhere
    {
        int jump_type = 0; // 0 is normal, 1 is duck roll,...

        if (duck_initialized)
        { //if in duck mode:
            if ((!left_down) && (!right_down)) { animationPlayer.PlayAnimation(jumpUpAnimation); animationPlayer.frameIndex = 2; ducking = false; duck_initialized = false; customAnimator.animation = null; isGrounded = false; }
            if ((!rolling) || ((Math.Abs(velocity.X) < 2)))
            {
                if (left_down)
                {
                    if (facing == FACE_LEFT) { animationPlayer.PlayAnimation(rollForwardAnimation); velocity.X = max_speed.X * -2; }
                    if (facing == FACE_RIGHT) { animationPlayer.PlayAnimationBackward(rollForwardAnimation); velocity.X = max_speed.X * -2; }
                    rolling = true;
                    jump_type = 1;
                }
                if (right_down)
                {
                    if (facing == FACE_RIGHT) { animationPlayer.PlayAnimation(rollForwardAnimation); velocity.X = max_speed.X * 2; }
                    if (facing == FACE_LEFT) { animationPlayer.PlayAnimationBackward(rollForwardAnimation); velocity.X = max_speed.X * 2; }
                    rolling = true;
                    jump_type = 1;
                }
            }
            else jump_type = 1;
        }
        if (jump_type == 0)
        {
            velocity.Y = -jumpPower;
            isJumping = true;
            if ((inWater) && ((animationPlayer.animation == jumpForwardAnimation) || (animationPlayer.animation == jumpUpAnimation))) animationPlayer.frameIndex = 0;
        }
    }
}
else if (isJumping)
{

 ....

... etc..

So I map the possible behaviors and conditions on paper first and use that to figure out how to build conditions.

ie: flip-roll from ledge -- relying on falling state and playing fall animation would be faulty.

Based on suggestions I'm thinking maybe it's possible to set legal animation bridges between frames in other ways which again I'm thinking may still require conditional inputs such as velocity, water-interaction state, grounded-state, jump-state, crouch-state(ie: just starting, far enough into, just ending), knowledge of surrounding objects and Booleans set to qualify legality of certain transitions. Right now I actually have it choose frame transitions differently depending on what's happening as it enters another animation to satisfy what the player wants to do.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!