• Advertisement
Sign in to follow this  

The best way to manage sprite sheet animations?

This topic is 879 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

Hello again,

 

Thank you for the code fragment renman29, it was very enlightning. I didn't realize it was taken to this kind of detail.

 

I believe state machines can be useful here, and I started to write a reply, but it somewhat exploded in length, and I wasn't even close to the end.

So instead I wrote it all down in a html file. It's not entirely finished, but please take a look, and let me know what you think.

 

 

[attachment=28604:state_machines_animation.zip]

Share this post


Link to post
Share on other sites

I'd just like to say thanks again for all the swift and very helpful replies. I certainly have a lot to work with here!

 

In regards to everything that's been said, I've already implemented a few of these concepts. I like to keep my sections

separate depending on what they do. For example, I handle all the input, whether that's from a controller, mouse, keyboard, or

AI command, then convert that into some kind of intent.

 

The intent can then be worked with once, so everything down the line doesn't have to keep checking for different types of input!

This intent can then drive the states of my entities, so, for example, say it has an enum for its different states (walking, still, jumping, attacking1,

attacking2, etc), the methods called after these checks don't have to check against 10-20 different variables, and instead just

check if the entity's state is a certain way.

 

For example, if I have 10 separate lines of code that need to know if I'm standing, it's better to have:

 

if (this, that, something else, another thing, some variables doing stuff, this is on, etc)

{

          currentState == PhysicalStates.Standing;

}

 

//Then further down the code

 

if (currentState == PhysicalStates.Standing)

{

         //Do something hilarious

}

 

Since every check to see if I'm standing only has to check the PhysicalStates enum. So in that respect, my code is data-driven

to some extent. I also separate the animation completely into its own method, so that the movement, collisions, etc, don't have bits

of animation code wedged in. I originally did that, and it was a nightmare to maintain the animation, especially when adding new

animations in that I hadn't previously accounted for. I'd have to change the code massively to account for a single line.

 

Using this approach, I then have a ChangeAnimation() method in each entity (abstractly inherited) which separately checks if

the animation should change after all the logic nitty gritty code has been executed.

 

I hope this helps anyone who's having trouble with animation themselves.

 

I have to say that Alberth's state machines write-up is immensely helpful! I think that implementing two state machines (one for logical states

and another for animation states) is the best way for me to go. As I previously said, my code worked, but it was a messy jumble of if nests.

It's a relief to know that there's no "simple" solution to this problem. But if I implement the state machine concept, I'm pretty sure there's no way

the animations could go wrong.

 

I'm also going to change my animation class to simply have preset animations. At the moment, it's more like:

 

if (currentState == PhysicalStates.Dying)

{

         animation.startPosX = 2;

         animation.startPosY = 3;

         animation.playSpeed = 5;

         animation.replay = false;

}

 

After looking into this, it seems a much more maintainable approach would be to link these variable changes to their own

state, so a newer version could simply be:

 

if (currentState == PhysicalStates.Dying)

{

         animation.Play("death");

}

 

The "death" animation would then essentially play an animation which was already defined as:

 

         animation.startPosX = 2;

         animation.startPosY = 3;

         animation.playSpeed = 5;

         animation.replay = false;

 

That's about my take on it anyway! Does this seem like the practical way to go about it? I want to make sure

I fully understand where people are going with this :)
 

Share this post


Link to post
Share on other sites

Yep, state machines are a serious tool in the box. But they also bring own problems. One big thing is that they tend to become unmanageable quickly due to state count explosion. That has led to mixed forms (e.g. the state is partly external to state nodes) and variants like the hierarchical state machines.

 


The "death" animation would then essentially play an animation which was already defined as:
 
         animation.startPosX = 2;
         animation.startPosY = 3;
         animation.playSpeed = 5;
         animation.replay = false;
 
That's about my take on it anyway! Does this seem like the practical way to go about it? I want to make sure
I fully understand where people are going with this

I'm not totally sure about the meaning of the shown lines of code. A neat thing about data driven design is that code need not necessarily be touched when changing things. Part of it is to load control data with the resources. E.g. if a sprite sheet is loaded then not only its texture but also its frame description table is loaded. If the sprite sheet is used as a flipbook animation, then also the sequence of frames and their basic timing should be loaded with the animation clip.

 

However, if you have an explicit initialization phase where the control data are written once because of the lack of a full resource loading system, then IMHO its fine so far, too.

Share this post


Link to post
Share on other sites

You already have a state explosion, it just doesn't look like a state machine, but takes the form of nested if/else branches and assignments, where you handle input, game character state, and animation state all at the same time.

 

The trick to avoid that, is to have more than one state machine (one for the game character, and one for the animations). That way you can think and define each aspect separately. The computer will then merge the states in runtime, where you don't care about the number of possible combinations, as there is always only exactly one combination active.

 

Alternatively, you merge the state machines off-line, but you typically need a code generator for that, and indeed you get the combinatorial explosion back, but it's likely not so big here, as game character states and animation states are tightly coupled. Also, if you generate it, it doesn't matter much as long as it fits in memory and the compiler can process it.

 

Edit: White space fix

Edited by Alberth

Share this post


Link to post
Share on other sites


The "death" animation would then essentially play an animation which was already defined as:
 
         animation.startPosX = 2;
         animation.startPosY = 3;
         animation.playSpeed = 5;
         animation.replay = false;
 

 

In more conceptual terms, these values should not be defined in the source code.  You need to use external data to define your animations, something like json (which has many parsers and is easy to work with and not overly-verbose like XML).  Then, you'd define your animations like this:

{"animations":[{"name":"death", "spritesheet":"death.png", "startPosX":2, "startPosY":3, "playSpeed":5, "replay":false}, 
                       {"name":"walking", "spritesheet":"walking.png", "startPosX":1, ...} ...]
}

Obviously, it can be more than that, but doing it that way you don't have to re-compile every time.  Then, in your animations constructor (or Init, whatever), you can load all the animations and define them using the animation json file(s).

 

(Oh, I see Haegarr said this, but I wanted to give an example).

 

Good luck!

Share this post


Link to post
Share on other sites

How exactly would you guys recommend going about attaching an animation to a key word? My animation

class contains all the information it needs for different animation strips. But say I made a method that takes a string:

 

//In animation class

 

public void SetAnimation(string inString)

{

         //Attach this string to a particular animation strip when initializing

         //Would only be called once

}

 

public void Play(string inString)

{

         //Play pre-defined animation strip linked to the string

}

 

What would you guys recommend to link the string to all the variables required for a whole animation: eg. startPosX, startPosY, frames, playSpeed, etc

Edited by zuhane

Share this post


Link to post
Share on other sites

Don't use strings, use animation objects. It looks like you're programming in Java, maybe an enumeration is best:
 

public class AnimationData {
    boolean loaded = false; // Set to true if loaded.
    
    public int  startPosX;
    public int startPosY;
    public int playSpeed;
    public boolean replay;
    
    public static enum Animations {
        FOO,
        BAR;
        
        private Animations() {
        }
        
        public final AnimationData animData = new AnimationData();
    }
}

You can reference the animation by the enum value FOO or BAR

The enum value has a 'animData' field contain all stuff you have for the animation.

public void play(Animation a) { play(a.animData); }
public void play(AnimationData a) {
  // use the data
}

play(FOO);

Edit: Added a second play method

Edited by Alberth

Share this post


Link to post
Share on other sites

I'm going to try this new approach! Should hopefully have quite a bit of free time this weekend, so I can put it to use.

 

I've started redoing a load of my code to be more data-driven and I've also started working on a state-managing system.

Will keep you updated with the latest. Thanks again for the help :D

Share this post


Link to post
Share on other sites

If all the animations are quite simple, I would make such arrays like SpritesheetX[animation][frame] and SpritesheetY[animation][frame], then init all them and go through each frame.

(So you can make them loop, non-loop, or like any short enough algorithm (This makes sense when the same sheet is used differently, that is quite common situation I guess))

This doesn't work well for slow animations though just like that.

For a case of slow animations I would make some counter that calls PerformSlowAnimation every, let's say, 10 ticks.

If the game is simple enough (in terms of animations), it might not matter if all animations are synchronized or not (they will be if you do so), and you can divide all animations onto fast, slow, very slow, etc.

 

If animation has very different frame rate during its life, you can always do a special method for this case. If there aren't much objects with "unstable" animations, you can design its behavior as just an additional functionality, so it doesn't have to work as fast as main method (so you can make if statements for that, switches, virtual calls or calls by pointers, whatever).

Edited by True_Krogoth

Share this post


Link to post
Share on other sites

(Just want to add) There are occasions when a string matching is (initially) useful - such as external animation editor which may have some unknown # of named animations and behavior definitions which the code knows how to use. You can pre-cache (store ahead of time) a match to a logic(if then conditions) determined animation. If you want to keep the string format, you can use an unordered map or dictionary (hash tables - very fast) to match the name/description with the desired animation. For animations that will switch frequently though you may want to have it store the matches ahead of time (micro-optimization) to the appropriate enums.

Good luck on your mission. :)

Share this post


Link to post
Share on other sites

I've essentially ripped my solution to shreds and I'm rebuilding almost all of it again to work in a more

state-driven way. I'll be looking at various guides that you've all linked me too, but I have a general idea of

how I want to design it:

 

In the base class for all entities (Entity.cs) there's a method which checks against certain conditions and then changes

states. For example, if an entity's velocity != Vector2.Zero, then I can set "physicalState = PhysicalStates.Moving", so that

all entities will follow this flow. I decided to make all the enums private, so that everything is all contained within this lower

layer to avoid potential confusion later on!

Share this post


Link to post
Share on other sites

Another interesting solution is using a stack for the animations.

 

The final animation for your character would be death. Let's say we push that at the bottom of the stack.

 

If I had as many states for my character as you, I would go as far as implementing each state as it's own class.

For example, the character starts in the idle state, and that state is also pushed onto the stack. Each animation state has at least two functions - start and update.

Start sets which animation to play.

Update controls when to exit or add a state. The idle state will only end in one condition - when the player life reaches zero.
From idle we can go to different other states, all launched from idle.

class IdleState : public AnimationState
{
    void Start() override
    {
       m_character.SetAnimation(idle); // idle could be a enum
    }

    bool Update() override
    {
       if (m_character.IsDead() == true) return false; // false will pop the state
       if (jump_button_pressed) m_character.AddState(new JumpState(m_character));
       if (IsFalling() == true) m_character.AddState(new FallState(m_character));          
       etc...
       return true;    
    }

    bool IsFalling()
    {
       return (m_character.OnGround() == false && m_character.GetVelocity().y > 0);
    }
}

In this way, all states will be encapsulated and it will be more easy to add or change existing states without interfering with player code or other states. Also, your entity class will be kept at a minimum size.

Each entity will need to have its own stack:

class Entity
{
     Stack<AnimationState> m_animationStateStack;

     void Update()
     {
           if (m_animationStateStat.top().Update() == false) m_animationStateStack.pop();
     }
}

Each state also need to know of the stateStack in order to add new states.

Share this post


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

  • Advertisement