Ok, this is just a quick End of Week brain dump
// IRenderable is the interface for your renderable components
public class CmpAnimation : IRenderable
{
// Updates the animation, Inherited from IRenderable
public bool Update(float ElapsedTime);
// Dumps your data into a render stream or whatever you do to render, Inherited from IRenderable
public bool Render();
// Called from Update when our current frames is
public bool OnAnimationComplete();> our End Frame value
// Some way to load the animation data, either the sprite sheet or a keyframe data file
public bool LoadAnimation(string AnimationName);
// The animation to go to once we are done with this one
public CmpAnimation NextLinkedAnimation { get; set; }
// Loaded values that you may want to change or access at run time
// The rate at which the animation plays
public float Rate { get; set; }
// The frame the animation starts on
public int BeginFrame { get; set; }
// The fame the animation ends on
public int EndFrame { get; set; }
// Does this animation loop until stopped by some external thing?
public bool CanLoop { get; set; }
// Informational values for internal or external use
public bool IsAtEnd { get; }
public bool IsAtStart { get; }
public bool IsPlaying { get; }
}
Basically Update() updates its internal state so advance the animation to where it should be for its time stamp, if it reaches the end it should then go to the next animation (mark it as active, deactivate this one.. however you want to do that part based on your component systems flow).
This lets you put your FSM in to data, the animations know where they exist within the data they have loaded (Good for having a single 'Jump' animation but where you want the jump to have 'Jump', 'Jumping', 'Falling' and 'Landing' at different key frame indexes within that data).
Again, end of the week brain dump to help get you going in the direction you want to go in :)
I hope this helps.