Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
AnimationChains represent a series of AnimationFrames which can be used to animate objects which implement the IAnimationChainAnimatable interface such as Sprites. AnimationChains can be created in code, or they can be created using the AnimationEditor. The AnimationEditor is installed when running the FlatRedBall installer which can be found on the downloads page. The IAnimationChainAnimatable page has more information on how to use AnimationChains, so please check it out after finishing up this page.
The following statement will help reduce code when working with AnimationChains.
AnimationChains can be created manually by creating the frames individually through code, by loading a .achx file, or through the content pipeline.
Notice that the .1f is the frame length in seconds. For from-file and content pipeline loading, see the AnimationChainList wiki entry.
Note: The AnimationFrame class is used to define individual frames in an AnimationChain. For more information on how to modify your animations, including how to create animations by using parts of a single Texture, see the AnimationFrame page.
For information on loading an AnimationChainList from a .achx file, see this page.
AnimationChains are also Lists of AnimationFrames. Therefore the AnimationChain provides the same interface as a list for accessing frames, such as indexing ( [index] ), properties like Count, and methods like Add. For example, the following code can be used to change the referenced texture of all frames in an animation chain to NewTexture :
FlatRedBall.Graphics.Animation.AnimationFrame - AnimationChains represent a list of AnimationFrames. When an AnimationChain is applied to an object, the object flips through and uses the AnimationFrames to modify its appearance.
FlatRedBall.Graphics.Animation.AnimationChainList - AnimationChainLists are lists of AnimationChains. Objects such as Sprites store AnimationChainLists, simplifying the process of setting which AnimationChain is currently used.
FlatRedBall.Content.AnimationChain.AnimationChainListSave - The "save" file for AnimationChainList files. This can be saved to and loaded from .achx files, and can also be converted to and from AnimationChainLists. For more information, see the FlatRedBall File Types wiki entry.
FlatRedBall.Graphics.Animation.IAnimationChainAnimatable - The interface that defines properties and members for objects which can be animated by AnimationChains. See this article for information on how to set animations on objects such as Sprites.
FlatRedBall.Sprite.PixelSize - PixelSize can be used to reactively set scale based off of a changed Texture resulting from playing an AnimationChain.
Did this article leave any questions unanswered? Post any question in our forums for a rapid response.
The Clone method can be used to make a copy of the AnimationChainList. This method is useful if your game needs to make copies of AnimationChainLists loaded from file. This is the case if the AnimationChainLists use the same texture coordinates, but simply use different Textures (such as different animation chains for characters in a game).
The following code example assumes that OriginalAnimationChainList is a valid AnimationChainList.
For more information see the AddDisposable page.
[subpages]
The FrameToFrame method returns the shortest absolute distance between two frame indexes. This value may be negative and considers looping. Example Assuming you have created an AnimationChain named "ac" with 6 AnimationFrames (the last at index 5), FrameToFrame returns the following values:
Call
Result
Explanation
ac.FrameToFrame(1, 2)
1
The closest distance from 1 to 2 is 1 frame.
ac.FrameToFrame(2, 1)
-1
The closest distance from 2 to 1 is -1. This value is negative because you must move "backward" to get from 2 to 1
ac.FrameToFrame(1, 5)
-2
The closest distance considering looping to get from 1 to 5 is -2. That is first going from 1 to 0, then 0 to 5 (the last frame)
ac.FrameToFrame(0, 3)
3
Although 0 is both 3 and -3 frames away from index 3, FrameToFrame doesn't wrap if the direct difference is equally short as the wrapped.
The total length obtained by adding the FrameTimes of all contained AnimationFrames.
Represents a list of AnimationChains. This object can be loaded from file and saved to file as well. This object is associated with the .achx file. For information on how to use AnimationChainLists in Glue, see this article. AnimationChains can be displayed by IAnimationChainAnimatables such as Sprites and SpriteFrames. For more information on how to work with AnimationChains in code, see the IAnimationChainAnimatables page.
AnimationChains can be loaded from .achx files which are created in the AnimationEditor. The following code creates an AnimationChain and assigns it to a Sprite. Add the following using statements to reduce code:
In Initialize after FlatRedBallServices.InitializeFlatRedBall:
For information on loading through the Content Pipeline, see the FlatRedBall XNA Content Pipeline wiki entry.
To save an AnimationChainList to file, you can use the AnimationChainListSave object. For more information, see this page.
Did this article leave any questions unanswered? Post any question in our forums for a rapid response.
The AnimationController class enables a game project to define animation logic using a modular approach as compared to a long chain of if/else if statements. The AnimationController was initially created to enable generated code to define animations while still allowing custom code to inject new animation behavior. Since its creation, the AnimationController has grown in capability, and it is currently the recommended way to create animation-assigning logic.
To help explain the benefit of using the AnimationController, consider the following code. It is typical code for controlling the animation for a character that can walk or stand idle in two directions (left and right)
Although the logic for setting the animationToSet is fairly simple, it suffers from not being very modular. That is, whether to assign the idle animations depends on the logic for whether to set the walking animations and whether the player is taking damage. Larger projects may want to organize logic for different types of animation assignment, or even take advantage of code generation for animation assignments. AnimationControllers provide a standard way to separate your animation code into modular pieces of code.
We can think of the code above as being organized into three layers. The top layer (the layer which has the first opportunity to set the animation) sets the taking damage animations. If it the top layer does not set an animation, then the if-check for setting the walk animations is performed. Finally if neither of the first two blocks set animations (which happens when the player is not taking damage and is walking less than 1 unit per second), then the bottom layer can set the idle animation. Games may have animations organized into multiple layers, where each layer has higher priority than layers underneath. For example the code above may would have the following layers:
TakeDamageAnimations
RunAnimations
IdleAnimations
In plain English this can be represented as:
If the player is taking damage, show damage animations. Otherwise... If the player is running, show the run animations. Otherwise... Show the Idle animations
Using an AnimationController is similar to writing a series of if/else if statements, but each layer can be independently defined in its own function, making the code more modular. For example, the above code could be rewritten using an AnimationController as shown in the following code:
The order in which the AnimationLayer instances are added controls the priority. The first layer added has the opportunity to set an animation. If its EveryFrameAction
returns a non-null value, then that layer's animation is assigned. If the layer returns null, then the next layer's EveryFrameAction
will be performed, and so on.
The code above which introduces how to add layers using AddLayer may seem similar to a similar if/else-if block. In fact, the order that AddLayer is called controls the priority of animations, so the AddLayer calls must be performed in this particular order. However, the benefit of the AnimationController is that layers can be added, removed, and reordered.
The AnimationController exposes its Layers property which can be used to perform any standard list operation. For example, consider a game where a certain type of enemy entity plays an animation when standing still and reloading. For this example we will assume that the derived enemy inherits from the base entity, and that the base animation logic should still apply. However, this derived enemy will check if it is reloading, and if so then it will play its reloading animation.
In this case the reloading animation has higher priority than the idle animations, but lower priority than walking and taking damage. To inject the animation, the following code may be added to the derived entity's CustomInitialize:
Note that this code assumes that the controller is either public or protected so that the derived entity can access it. This may be done in custom code by modifying the controller definition, or if the AnimationController is added through the FlatRedBall entity, then its ExposedInDerived property can be set to true.
Also, this code uses the Insert method with a magic number for the sake of simplicity, but a typical game may assign the Name property on layers, and find the index of the "Idle"
AnimationLayer to dynamically insert the new reload layer at the correct index.
The Texture property is a reference to the Texture2D referenced by an AnimationFrame. This is the Texture that it will apply when the animation is being displayed. This is automatically set when loading a .achx file (such as in Glue), but it can be changed at runtime, or can be set when creating a new frame.
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.
AnimationFrames represent the state of an IAnimationChainAnimatable. The following properties can be set by an AnimationFrame:
Texture
RelativeX/Y Position
Texture Coordinates
Horizontal/Vertical Flipping
AnimationFrames usually exist inside AnimationChains.
AnimationFrame instances are typically contained in AnimationChains, and are created by loading a .achx file. AnimationFrames can be constructed in code, and can be added to AnimationChains (see below).
Although .achx files are the most common way to create AnimationFrames and AnimationChains, AnimationFrames can also be constructed in code. The following code shows how to construct an AnimationChain and AnimationFrame in code, assign it to an existing Sprite, and update the Sprite to the AnimationChain:
The FrameLength property defines how long an AnimationFrame is displayed. Adding the FrameLengths of all AnimationFrames in an AnimationChain results in the length of the entire animation. FrameLength - like all timing in FlatRedBall - is performed in seconds. Therefore, if an AnimationFrame has a FrameLength of 1, the AnimationFrame will show for 1 second. If you are familiar with working in milliseconds, then simply divide the desired value by 1,000. For example, to set the FrameLength to 600 millseconds, simply divide 600 by 1,000 and set that value to your FrameLength:
A ShapeCollectionSave instance which can be used to apply a frame's collision to an entity. By default this is null.
The most common usage is to add shapes to an AnimationChainListSave file (.achx) and to apply animations to a collidable Entity. The following example assumes that shapes have been added to a frame in the AnimationEditor.
The code performs null checks (through the null coalescing operator), since a frame may not have collision data. If a frame does not have collision data, then the collision will not be modified. Note that if one frame does have collision, but subsequent frames do not, then the collision will remain unchanged when the later frames are played. Therefore, if one frame has collision, other frames should as well to avoid confusing behavior.
The RelativeX and RelativeY values in an AnimationFrame can be used to offset an animated object on a per-frame basis. This is useful if the images that are being used for the animation do not line up as desired. The relative values can be set by code or in the AnimationEditor.
Simply setting the RelativeX and RelativeY values on an AnimationFrame is not sufficient to change the position of an IAnimationChainAnimatable (such as a Sprite. The following conditions must be met:
The object (such as the Sprite) that is displaying the animation must be attached to another PositionedObject.
The UseAnimationRelativePosition property must be true.
If you are using objects created in Glue, then both of the above will usually be true.
The following code creates an AnimationFrame which displays the four quadrants of a redball.bmp graphic, then displays it in its entirety. The RelativeX and RelativeY values are used to offset the frames which display a single quadrant. Notice that the animated Sprite must be attached to an object and that the Sprite's UseAnimationRelativePosition property must be set to true.
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.
The following shows various ways to set a Sprite's current AnimationChain. 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 AnimationChains, see the Creating AnimationChains wiki Entry.
Normally the Sprite's AnimationChains can be set in Glue; however, to set them manually in code:
IAnimationChainAnimatables like Sprites can also have their AnimationChains set after they are created:
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 SetAnimationChain or setting the CurrentChainName needs to only be called when the AnimationChain is changing or being set. It does not need to be called every frame to keep the animation going.
See FlatRedBall.Graphics.Animation.IAnimationChainAnimatable.CurrentFrameIndex.
When an IAnimationChainAnimatable changes the AnimationFrame that it is displaying, its JustChangedFrame property is true for that frame.
Walk North
Walk South
Walk West
Walk East
Attack (likely also has directions, but not included to save space)
Die
Since these behaviors share many similarities they should be put in a base class. However, setting AnimationChains becomes a problem. If each type of object (human peasant, orc peasant, ogre) references different AnimationChains 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 AnimationChain 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 AnimationEditor can use the same names for their AnimationChains. 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 AnimationChains. What the AnimationChain holds internally is insignificant from the programmer's point of view, just the name. Once these AnimationChains are created, the code simply loads the appropriate .achx file in the derived class' constructor. The base class can set the current AnimationChains 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 AnimationChain setting with no regard to the actual contents of the AnimationChain being set.
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:
Did this article leave any questions unanswered? Post any question in our forums for a rapid response.
Objects which implement the IAnimationChainAnimatable interface hold an AnimationChainList reference internally. This AnimationChainList is referenced by IAnimationChainAnimatables to standardize the setting of AnimationChains according to state or behavior. The game Warcraft 2 will be used as an example of how the internal storage of AnimationChains can standardize code and simplify development. Warcraft 2 has numerous characters which share similar behavior. All ground units have the following behavior:
The list of AnimationChains referenced by this instance.
The Animate property returns whether the IAnimationChainAnimatable is performing animation (cycling through AnimationFrames). 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.
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:
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.
A Sprite's AnimationSpeed can be changed in the FlatRedBall Editor in the Variables tab.
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).
Assuming that mSprite is a valid Sprite that has a current AnimationChain the following code will manually cycle the Frames:
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
The CurrentChainName property gets and sets the name of the AnimationChain 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 Sprite).
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.
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.
Keep in mind that some properties will not change in response to CurrentChainName being set:
JustCycled
JustChangedFrame
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:
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.
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.
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:
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:
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: