Animations Part 2 – Animations from code
So for this next post I will be talking about animations from code. This system allows programmers to apply very basic (but also complex) animations to manipulate data over time. The system is mostly used for simple fading, moving and stuff like that.
The system is loosely based on the animation system in WPF and the animation system from Ditigal Rune although their system is much more advanced. The basic idea is that a programmer defines a simple animation like ‘change a to b in so many seconds’ and then let the system apply the animation to some data (as long as the types match of course). The system is completely generic and it is used for all animations (even sprite-sheets and skeletal animations) within the engine/game.
It will be hard to explain how the system works completely but in this post I will give two examples from which I hope other developers can extrapolate the rest (if not, do ask). If your not a programmer then you should also read on frankly because, your programmers should implement such a system as quickly as possible. 😛
Simple example
So lets start with the first example on how to use the system. In the following example a field called position is animated by changing its value from (0,0) to (100,100) in 3 seconds using standard linear interpolation. I hope the comments are pretty self explanatory.
// Define an animation that moves from (0,0) to (100,100) in 3 seconds var moveAnimation = new Vector2FromToAnimation(Vector2.Zero, new Vector2(100, 100), 3.0f); // Lets say we have a field named position somewhere. // We have to create an animatable wrapper for it. This creates a // delegate animation property which specifies how to get and set the // data. var positionProperty = new DelegateAnimationProperty<Vector2> (() => return position, // Lambda function to return position (value) => position = value);// Lambda function to set the position // Finally, play the animation using the IAnimationService interface. animationService.StartAnimation(moveAnimation, positionProperty);
Thats it. All it takes is 3 lines of code. Some of you may notice that using the system is pretty similar to how the Digital Rune engine work. That is completely true for we used that a lot for inspiration.
Sprite-sheet animation
The second example I want to show is how we use this system for sprite-sheet animations. Sprite-sheet animations are basically keyframe animations of different frames of a spritesheet. Our system also supports generic keyframe animations which makes this really easy. All that is required is that we define a proper datatype to animate. Our datatype looks somewhat like this:
struct SpriteAnimationFrame { // The source rectangle in the sprite-sheet public Rectangle SourceRectangle; // The origin of the sprite within the SourceRectangle public Vector2 Origin; // The spritesheet texture (animations can be cross spritesheet) public Texture2D Spritesheet; }
The next step is to animate this data. Because the system doesn’t know how to perform mathematical operations on the datatype this has to be specified. I’m not going into the details but its basically a generic class that implements these basic operations on this datatype. Note that most standard operations (like add or multiply) cannot be performed on this datatype so those methods simply throw a NotSupportedException.
Now that the animation system knows how to work with our animation data we can start animating this.
// Suppose we have a collection of SpriteAnimationFrame's called frames. // Create a keyframe animation that displays a new frame every 100 ms. var spriteAnimation = new KeyFrameAnimation<SpriteAnimationFrame>(); spriteAnimation.Add(0, frames[0]); spriteAnimation.Add(0.1, frames[1]); spriteAnimation.Add(0.2, frames[2]); spriteAnimation.Add(0.3, frames[3]); spriteAnimation.Add(0.4, frames[4]); // We also have a SpriteAnimationFrame animatable property called // animationState similar to the one we created in the previous // example. animationService.StartAnimation(spriteAnimation, animationState);
Again, thats all there is to it. We can now use the data in the animationState property to show the proper frame of the animation over time.
Looping animations
Another useful thing we implemented is the ability to loop animations. We achieve this by wrapping an animation in an AnimationClip. This animation can have a different duration. If this duration is longer than the wrapped animation, the wrapped animation is looped.
To conclude
All in all, I have come to absolutely adore this system. It saves me a tremendous amount of work to add quite a lot of animated detail to our games.
Sorry for this somewhat more technical talk. Next time I will be talking about skeletal animation with less code and more examples. 😛
If you have questions, drop them in the comment box below or just send me an email. 🙂
Cheers!
blog comments powered by Disqus