Animatable Objects and Properties |
The purpose of the animation system is to animate other object and properties, i.e. to change their values over time in a controlled fashion.
Animations can be applied to objects that implement the interface IAnimatableObject or properties that implement IAnimatablePropertyT.
Note |
---|
All objects of the DigitalRune Game Object System and all UI controls of DigitalRune Game UI already implement the interfaces IAnimatableObject and IAnimatablePropertyT. GameObjects and UIControls implement IAnimatableObject. These objects can be animated directly by the animation system. A GamePropertyT can be cast to IAnimatablePropertyT by calling GamePropertyTAsAnimatable. This can be necessary if an animation should be applied directly to a specific property. |
There are several helper classes that provide implementations of the interface IAnimatablePropertyT, so in most cases it is not necessary to implement this interface directly.
The helper class AnimatablePropertyT can be used to create a new (stand-alone) animatable property. It is basically just a container storing a value.
// Create new property which can be animated. AnimatableProperty<Vector3F> position = new AnimatableProperty<Vector3F>(); // The AnimatableProperty<T> is just a wrapper over a another type. position.Value = new Vector3F(1.0f, 2.0f, 3.0f);
The DelegateAnimatablePropertyT is a helper class can be used to make an existing field or property accessible for the animation system. It does not directly store a value, instead it stores two callbacks that read or write the value.
For example, imagine an existing class that represents a Sprite:
public class Sprite { public Color Color { get; set; } public Vector2 Position { get; set; } public Texture2D Texture { get; set; } }
In order to animate the Position, the property needs to be wrapped using a DelegateAnimatablePropertyT:
// Lets create a new Sprite. var sprite = new Sprite(); // To animate the Sprite's position, we need to create an IAnimatableProperty<Vector2>. var animatablePosition = new DelegateAnimatableProperty<Vector2>( () => sprite.Position, // A getter that reads the value. v => sprite.Position = v); // A setter that writes the value.
A property needs to implement IAnimatablePropertyT in order to be animated. The interface has two main properties: BaseValue and AnimationValue. That means, an animatable property can have a base value and an animation value.
Base Value: The base value is the value of the property that is valid when no animations are active. The base value is optional - not all properties that implement IAnimatablePropertyT need to have a base value. The properties HasBaseValue and BaseValue need to be set by the object that implements the interface. The animation system reads the base value but does not change it. The base value is used by certain types of animations: For example, additive animations will add the result of the animations to the base value value. Another example are "From-To-Animations": If only the "To" value is defined then the animation will animate from the base value of the property to the "To" value defined in the animation.
Animation Value: The animation value of the property is determined by the animations that are controlling the property. The properties IsAnimated and AnimationValue are set by the animations system and should be treated as read-only. IsAnimated is true when an animation is active; false indicates that no animations are active. In this case the base value, if available, should be treated as the effective value of the property.
Note that not all types that implement IAnimatablePropertyT have a base value. Some implementations such as AnimatablePropertyT do, some implementations such as DelegateAnimatablePropertyT don't! If a property stores a base value and all animations are stopped, the property value reverts to the base value. If the property does not have a base value and all animations are stopped, the property value retains the most recent animation value.
Properties that do not store a base value, only an animation value, are sometimes called "pure animated properties".
Users never have to deal with the interface IAnimatablePropertyT directly - except when they want to implement their own type of animatable property.
The interface IAnimatableObject indicates that an object has properties that implement IAnimatablePropertyT. Objects that implement IAnimatableObject have several advantages: Animations that affect multiple properties can be group together as one animation ("storyboard"). A complex storyboard can be treated as a single animation.
Here is an example that shows how a class that implements IAnimatableObject could look like. In this example the color and position of a sprite can be animated.
public class AnimatableSprite : IAnimatableObject { private readonly AnimatableProperty<Color> _color = new AnimatableProperty<Color>(); private readonly AnimatableProperty<Vector2> _position = new AnimatableProperty<Vector2>(); public string Name { get; set; } public Color Color { get { return _color.Value; } set { _color.Value = value; } } public Vector2 Position { get { return _position.Value; } set { _position.Value = value; } } public Texture2D Texture { get; set; } public IEnumerable<IAnimatableProperty> GetAnimatedProperties() { yield return _color; yield return _position; } public IAnimatableProperty<T> GetAnimatableProperty<T>(string name) { switch (name) { case "Color": return _animatableColor as IAnimatableProperty<T>; case "Position": return _animatablePosition as IAnimatableProperty<T>; default: return null; } } }