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.
[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:
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:
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 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.
If you are using objects created in Glue, then both of the above will usually be true.
Simply setting the RelativeX and RelativeY values on an AnimationFrame is not sufficient to change the position of an (such as a . The following conditions must be met:
The object (such as the ) that is displaying the animation must be attached to another PositionedObject.
The property must 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 must be attached to an object and that the UseAnimationRelativePosition property must be set to true.
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.