All pages
Powered by GitBook
1 of 10

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Animation and Timing

IAnimationChainAnimatable-implementing objects should automatically update their displayed frame according to time. It is possible that a frame may last less than one frame of game time - if the game is running slowly or if the frame is of very short duration. Sprites, for example, will skip frames if the timing advances far enough. Not all frames are guaranteed to play.

AnimationChains

The list of AnimationChains referenced by this instance.

AnimationSpeed

Introduction

The AnimationSpeed property controls the speed at which an Animation is playing. The default value for AnimationSpeed is 1, which means the amount of time that each AnimationFrame displays is equal to its FrameLength property.

  • Increasing this value above 1 will make animations play faster.

  • Setting this value between 0 and 1 will make animations play slower.

  • Setting this value to 0 will make animations stop (similar to setting Animate to false).

  • Setting this value to a negative number will make animations play in reverse.

Example - Setting AnimationSpeed in FlatRedBall Editor

A Sprite's AnimationSpeed can be changed in the FlatRedBall Editor in the Variables tab.

Animate

Introduction

The Animate property returns whether the IAnimationChainAnimatable is performing animation (cycling through ). This property does not reflect whether the IAnimationChainAnimatable has a CurrentChain. If it does not, this value may still be true indicating that the IAnimationChainAnimatable will animate once a CurrentChain is set.

Setting Animate

The IAnimationChainAnimatable interface only requires that the Animate property returns a value - it doesn't require a setter; however, common IAnimationChainAnimatable-implementing classes like Sprite and SpriteFrame provide a setter. If the specific implementing class allows, setting this value to false will prevent animation from occurring, and will stop any existing animation. For example, the following code can be used to toggle whether a Sprite is animating:

AnimationFrames
// assuming mySprite is a valid Sprite
if(GuiManager.Cursor.PrimaryClick)
{
   mySprite.Animate = !mySprite.Animate;
}

UseAnimationRelativePosition

The UseAnimationRelativePosition property controls whether the IAnimationChainAnimatable sets its relative values when the current AnimationChain changes its displayed frame. This value is true by default for the Sprite object. If you are applying relative values to an object such as a Sprite and do not want the AnimationChain to interfere, then set this value to false in code:

SpriteInstance.UseAnimationRelativePosition = false;

JustChangedFrame

Introduction

The JustChangedFrame property returns whether the frame index was changed this frame. This property can be checked every frame and action can be performed according to whether it has been changed.

Code Example

The following assumes that SpriteInstance is a valid Sprite which is animating:

CurrentChainName

Introduction

The CurrentChainName property gets and sets the name of the currently played by the owner of the property. Setting this property is the most common way to change between different animations at runtime, and it can also be set in Glue to control the animation displayed by an IAnimationChainAnimatable (such as a ).

if(SpriteInstance.JustChangedFrame)
{
   int frameIndex = SpriteInstance.CurrentFrameIndex;
   // do something with frameIndex:
}
Code Example

The CurrentChainName property is a string, so code can assign animation chains in a way that is not tied to the underlying content. The following code shows how to set the animation of an object according to pressed keys.

What does ChangingCurrentChainName do?

Changing CurrentChainName does a number of things:

  • Sets the displayed animation to the animation matching the set name.

  • Restarts the animation from the very beginning.

  • Immediately updates the IAnimationChainAnimatable's textures and texture coordinates to reflect the first frame in the animation.

Note that these actions are only taken if the CurrentChainName *changes. *Assigning CurrentChainName to the same value performs no logic, so it can be safely set every frame without restarting the animation from the beginning. To restart the animation from the beginning, set CurrentFrameIndex to 0.

What does setting CurrentChainName not do?

Keep in mind that some properties will not change in response to CurrentChainName being set:

  • JustCycled

  • JustChangedFrame

AnimationChain
Sprite
// Assuming that SpriteInstance is a valid Sprite, and that SpriteInstance contains animations with the name WalkLeft and WalkRight
if(InputManager.Keyboard.KeyDown(Keys.Right))
{
   SpriteInstance.CurrentChainName = "WalkRight";
}
else if(InputManager.Keyboard.KeyDown(Keys.Left))
{
   SpriteInstance.CurrentChainName = "WalkLeft";
}

CurrentFrameIndex

Introduction

The CurrentFrameIndex gets and sets the current frame that the IAnimationChainAnimatable is displaying. As animation plays this property will automatically increment and cycle. This value will always be between 0 and the count of the current AnimationChain minus one (inclusive).

Manually setting CurrentFrameIndex

Assuming that mSprite is a valid Sprite that has a current AnimationChain the following code will manually cycle the Frames:

Restarting an Animation

Restarting the animation can be done either by setting the CurrentFrameIndex to 0 or by setting the CurrentChainName so long as the CurrentChainName differs from the set value. That means if your current animation is "DesiredAnimation" and you want to restart the animation you can either:

OR

 // Set Animate to false so that it doesn't automatically animate on its own:
 mSprite.Animate = false;

 if (InputManager.Keyboard.KeyDown(Keys.Up))
 {
     mSprite.CurrentFrameIndex = 
         ( mSprite.CurrentFrameIndex + 1 ) % mSprite.CurrentChain.Count;
 }
 if (InputManager.Keyboard.KeyDown(Keys.Down))
 {
     mSprite.CurrentFrameIndex--;

     if (mSprite.CurrentFrameIndex < 0)
     {
         mSprite.CurrentFrameIndex = mSprite.CurrentChain.Count - 1;
     }
 }
// So long as CurrentChainName differs from "DesiredAnimation"
someAnimatableObject.CurrentChainName = "DesiredAnimation";
someAnimatableobject.CurrentFrameIndex = 0;

IAnimationChainAnimatable

Introduction

The IAnimationChainAnimatable interface defines methods and properties for objects which can be animated by AnimationChains (which are stored in a AnimationChainList). Examples of classes which implement the IAnimationChainAnimatable interface include the Sprite and SpriteFrame.

Setting AnimationChains

The following shows various ways to set a current . The reason there are so many examples is because Sprites and AnimationChains can be created many different ways. What follows are examples which cover the most common scenarios. For information on how to create , see the .

If the Sprite and .achx are created in Glue

Normally the Sprite's AnimationChains can be set in Glue; however, to set them manually in code:

If the Sprite is already created (usually the case when using Glue), and you have an AnimationChain variable

IAnimationChainAnimatables like can also have their AnimationChains set after they are created:

If creating the Sprite in Code

If the Sprite has already had its AnimationChains property set (usually done through Glue)

If the Sprite has had its AnimationChains value set, either in code or in Glue, then you can simply select which animation to play:

Calling or setting the CurrentChainName needs to only be called when the is changing or being set. It does not need to be called every frame to keep the animation going.

Manually Setting Frames

See .

Detecting When an AnimationFrame Changes

When an IAnimationChainAnimatable changes the AnimationFrame that it is displaying, its JustChangedFrame property is true for that frame.

Internal AnimationChainList and Common Usage

Objects which implement the IAnimationChainAnimatable interface hold an AnimationChainList reference internally. This AnimationChainList is referenced by IAnimationChainAnimatables to standardize the setting of according to state or behavior. The game Warcraft 2 will be used as an example of how the internal storage of can standardize code and simplify development. Warcraft 2 has numerous characters which share similar behavior. All ground units have the following behavior:

  • Walk North

  • Walk South

  • Walk West

  • Walk East

Since these behaviors share many similarities they should be put in a base class. However, setting becomes a problem. If each type of object (human peasant, orc peasant, ogre) references different the the code cannot fully be standardized if references are used to set the current animation. That is, if methods are called when a state change occurs, there will need to be virtual methods that can be called by the base class to set the current to the appropriate reference. While this will work, it is not very convenient or readable - for a new user to understand the behavior he will have to traverse multiple files and follow the execution path up and down the inheritance tree. The alternative is to recognize early on that this similarity between objects exists and design for this standard behavior both in content and in code. In other words, if the behaviors previously listed in bullet points are recognized early on before content creation begins, then this pattern can be used when all AnimationChainLists are created. Once the textures for all animations are created, the .achx file created in the can use the same names for their . Therefore, the humanPeasant.achx file and the orc.achx file will both reference different textures, and can even have a different number of textures or frame times, but they should include a set of same-named . What the holds internally is insignificant from the programmer's point of view, just the name. Once these are created, the code simply loads the appropriate .achx file in the derived class' constructor. The base class can set the current using the Name property. As an example, the following code would work for all objects which have walking and dying animations:

So long as all objects which inherit from the class containing this code have AnimationChains named WalkNorth, WalkSouth, WalkWest, WalkEast, Attack, and Die, this code will handle all setting with no regard to the actual contents of the being set.

Adding AnimationChains to an IAnimationChainAnimatable

The previous section discusses how to set AnimationChains on an IAnimationChainAnimatable. Of course, for the CurrentChainName property to work, the IAnimationChainAnimatable must have a reference to an AnimationChain with a matching name. Another way of looking at it is that if you are going to toggle between AnimationChains, then the object that is going to have its AnimationChain set must have references to multiple AnimationChains. How can this be done? The most common and data-driven approach is to load a .achx file created in the AnimationEditor or some other tool. The .achx file can contain multiple AnimationChains so this greatly simplifies the process. However, it's also possible to set up your IAnimationChainAnimatable to use multiple AnimationChains if you are creating the AnimationChains by hand. To do this, you can simply add each AnimationChain to the AnimationChains property. For example, assuming that animationChain1, animationChain2, and animationChain3 are valid AnimationChains:

Additional Information

IAnimationChainAnimatable Members

Did this article leave any questions unanswered? Post any question in our for a rapid response.

JustCycled

Introduction

The JustCycled property is a property which is usually false, but will be set to true when an animation either finishes or cycles. This can be used to perform logic whenever an AnimationChain ends. By default, objects (such as Sprites) which play animations will automatically loop. When this happens, the object begins displaying the first frame in the animation. When this occurs, the JustCycled property will be true. Keep in mind that when this value is set to true, the object will display the first frame of animation that frame. It is possible to prevent this by performing logic (such as destroying the object) when this is true.

Code Example

The JustCycled property reports whether an object that is displaying an AnimationChain has just reached the end of an animation and has cycled to the beginning. You can perform logic in response this being set to true. The following code assumes MySprite is a valid Sprite. The if statement will trigger when the Sprite completes.

Using JustCycled to play an animation just one time

JustCycled can be used to play an animation once, then stop the animation when it's cycled. For this example we'll use an animating Sprite called MySprite:

JustCycled does not change after setting a new AnimationChain

If you are changing which animation an object is showing when JustCycled is set to true, keep in mind that JustCycled will stay true for the entire frame, regardless of whether you change chains in code. For example:

JustCycled and CurrentFrameIndex

When JustCycled is true and if the displayed object has its Cycling set to true, then CurrentFrameIndex will be 0 (unless an animation is playing backwards). In a typical setup (in an unmodified FlatRedBall template), the FlatRedBall Engine will perform its logic before custom game logic is executed every frame. This means that if JustCycled is true, custom code will have an opportunity to react to the cycle before the animation visually starts over. For example, consider this code:

Attack (likely also has directions, but not included to save space)

  • Die

  • FlatRedBall.Graphics.Animation.IAnimationChainAnimatable.CurrentFrameIndex

  • FlatRedBall.Graphics.Animation.IAnimationChainAnimatable.JustChangedFrame

  • FlatRedBall.Graphics.Animation.IAnimationChainAnimatable.JustCycled

  • Sprite's
    AnimationChain
    AnimationChains
    Creating AnimationChains wiki Entry
    Sprites
    SetAnimationChain
    AnimationChain
    FlatRedBall.Graphics.Animation.IAnimationChainAnimatable.CurrentFrameIndex
    AnimationChains
    AnimationChains
    AnimationChains
    AnimationChains
    AnimationChain
    AnimationEditor
    AnimationChains
    AnimationChains
    AnimationChain
    AnimationChains
    AnimationChains
    AnimationChain
    AnimationChain
    Animation and Timing
    FlatRedBall.Graphics.Animation.IAnimationChainAnimatable.Animate
    FlatRedBall.Graphics.Animation.IAnimationChainAnimatable.AnimationChains
    FlatRedBall.Graphics.Animation.IAnimationChainAnimatable.AnimationSpeed
    FlatRedBall.Graphics.Animation.IAnimationChainAnimatable.CurrentChainName
    forums
    AnimatedDrone.png
    Warcraft2 Screenshot.jpg
    SpriteInstance.AnimationChains = AnimationChainFile;
    SpriteInstance.Animate = true;
    SpriteInstance.CurrentChainName = "WalkUp";
    // This code assumes that animationChain is a valid AnimationChain and
    // sprite is a valid Sprite.
    sprite.SetAnimationChain(chainToSet);
    sprite.Animate = true; // still have to set animate to true
    // This code assumes animationChain is a valid AnimationChain.
    Sprite sprite = SpriteManager.AddSprite(animationChain);
    sprite.Animate = true;
    // So details can be seen
    sprite.ScaleX = sprite.ScaleY = 10;
    sprite.CurrentChainName = "WalkNorth";
    // assume mySprite is a valid Sprite that is animating
    if(mySprite.JustChangedFrame)
    {
       switch(mySprite.CurrentFrameIndex)
       {
           case 0:
               // do something
               break;
           case 1:
               // do something else
               break;
       }
    }
    // Assumes all types like BaseEntityState have been defined
    void SetState(BaseEntityState state)
    {
        // Assumes that the object has a reference to a Sprite called mSprite
        switch(state)
        {
            case BaseEntityState.WalkNorth:
                mSprite.CurrentChainName = "WalkNorth";
                break;
    
            case BaseEntityState.WalkSouth:
                mSprite.CurrentChainName = "WalkSouth";
                break;
    
            case BaseEntityState.WalkWest:
                mSprite.CurrentChainName = "WalkWest";
                break;
    
            case BaseEntityState.WalkEast:
                mSprite.CurrentChainName = "WalkEast";
                break;
    
            case BaseEntityState.Attack:
                mSprite.CurrentChainName = "Attack";
                break;
    
            case BaseEntityState.Die:
                mSprite.CurrentChainName = "Die";
                break;
        }
    }
    // Also assuming that mySprite is a valid Sprite (which implements IAnimationChainAnimatable)
    mySprite.AnimationChains.Add(animationChain1);
    mySprite.AnimationChains.Add(animationChain2);
    mySprite.AnimationChains.Add(animationChain3);
    // assume MySprite is a valid Sprite that is animating
    if(MySprite.JustCycled)
    {
       // code goes here.
    }
    if(MySprite.JustCycled)
    {
       MySprite.Animate = false;
       // The sprite animation will have cycled back to the first frame
       // To keep it at the last frame:
       MySprite.CurrentFrameIndex = MySprite.CurrentChain.Count - 1;
    }
    // This code checks to see if it's time to play the PerformPunch animation
    // by testing if the Sprite has just finished cycling...
    if(sprite.JustCycled && sprite.CurrentChainName == "StartPunch")
    {
        // ... if so, then the PerformPunch animation is set...
        sprite.CurrentChainName = "PerformPunch";
        // ... however, JustCycled is still true at this point...
    }
    // ... which means this if-statement will always evaluate to true immediately
    if(sprite.JustCycled && sprite.CurrentChainName == "PerformPunch")
    {
        // ... and the Sprite will immediately go into the Idle animation
        sprite.CurrentChainName = "Idle";
    }
    if(SpriteInstance.JustCycled)
    {
       SpriteInstance.Visible = false;
    }
    <pre>
    
    The code above will hide the Sprite after it has cycled, so the first frame of the animation will not show again.