Welcome to MSDN Blogs Sign in | Join | Help

ZoomEngine.Animation Part 2

In my last post I presented my declarative XNA animation library called ZoomEngine.Animation.  This time I want to step back and look at how all of the pieces fit together, and show how you can extend the library in your own game.

Lets start with the class diagram:

AnimationClassDiagram

ClockManager is the object that ‘owns’ all active clocks, and is responsible for updating when it’s Update method is called (typically once per game update).  This object acts as a scope for active clocks so that its easy to pause all the ‘level’ animations while keeping the animations running in the pause menu.

Clock is the base class for basically everything else.  It’s called ‘Clock’ because it defines how its internal time progresses with respect to your GameTime.  Properties of this type dictate when the animation starts and how long it runs.  Methods on this type allow you to start, stop and pause the clock/animation.

Timer is a simple type of clock that fires an event when it completes.  This is an easy way to schedule game events to happen in the future.

Animation<T> is the base type for all true animations.  It adds to the notion of time (provided by Clock), the ability to compute & apply a value of type T.  It is an abstract class because it doesn’t actually know how to compute the value, it simply provides an abstract method GetCurrentValue() for this purpose.

FromToAnimation<T> is the base class of all animation the define how to compute a current value using a From & To property.  All of it’s derived types are there to say exactly how to interpolate between From and To based on the current progress.  The Interpolate property is a delegate that lets you override the default behavior of linear interpolation without having to derive a whole new type.  This can be used to add some randomness to your animation, for example.

ProgressTransforms is a static class that provides several stock ProgressTransforms which can be used with an Animation<T>.

 

As you can see, this library is pretty simple when it comes down to it.  Some ways you might extend it would be to add a new type that derives from FromToAnimation<T>.  Another way you might extend this library would be to create a new ‘kind’ of animation such as KeyFrameAnimation<T>.  We’ll dive into the details of how to do this in another post.

Posted by brandf | 0 Comments
Filed under: , ,

ZoomEngine.Animation Part 1

ZoomEngine.Animation is a lightweight, easy to use, and powerful declarative animation library for XNA Game Studio.

As a gift for those who found my newly revived blog, I decided to share it with you.  It’s a small part of a larger game engine called ‘ZoomEngine’, but it doesn’t have any dependencies on the rest of the engine so I thought it would be a good candidate to share.  Hopefully down the line I’ll pull out more of our engine to share.

NOTE: This is from my personal game engine, and not something that’s in any way affiliated or supported by Microsoft.

In Part 1 of this series I will go over the basics of how to use this animation library in your game, and in subsequent posts I’ll go into more details on some of the advanced features and how you can extend the library.

So you may be asking yourself “what is a declarative animation library?”  To answer this, lets first look at how ZoomEngine.Animation is used.

    1                 var positionAnim = new Vector2FromToAnimation(clockManager)

    2                 {

    3                     From              = item.Position,

    4                     To                = new Vector2(item.Position.X + 600, item.Position.Y),

    5                     Duration          = 2,

    6                 };

    7 

    8                 positionAnim.Start();

You can see from the code above, by ‘declarative’ I mean that properties on the animation object determine what range of values the animation produces as time goes on.  The properties are declared before the animation begins, and are not typically changed during the animation (although this is possible).

Take notice of the naming of the type Vector2FromToAnimation.  The convention I use for the animation types is [TypeBeingAnimated][KindOfAnimation]Animation.  In this library an ‘animation’ is an object that produces values of a specific type (TypeBeingAnimated).  The ‘FromTo’ part indicates how you specify the range of values.  In this case it’s by specifying the From/To properties for the endpoints of a linear interpolation.  Another example of “KindOfAnimation” would be KeyFrame.  We’ll talk more about this in a later post.

Q: What does the above animation do?
A: Basically nothing.  I said that animations produce values, but we haven’t yet told the animation what to do with the values.  The next bit of code will show you how to apply the produced value.

    1                 var positionAnim = new Vector2FromToAnimation(clockManager)

    2                 {

    3                     From              = item.Position,

    4                     To                = new Vector2(item.Position.X + 600, item.Position.Y),

    5                     Duration          = 2,

    6                     Apply             = (v) => item.Position = v,

    7                 };

    8 

    9                 positionAnim.Start();

The Apply property is a delegate of type Action<T> where T is the TypeBeingAnimated.  This delegate gets called each time the ClockManager is Updated, and the new animated value is passed as the ‘v’ parameter.  You can do whatever you want with this value, but typically it is directly applied to a property on an object (like item.Position).  In this case the above animation will slide the Position of ‘item’ to the right by 600 units over a duration of 2 seconds.

Simple linear animations are lame, so lets now look at a more interesting example.

    1                 var colorAnim = new ColorFromToAnimation(clockManager)

    2                 {

    3                     From              = item.Color,

    4                     To                = Color.Firebrick,

    5                     Duration          = 2,

    6                     ProgressTransform = ProgressTransforms.Snake,

    7                     AutoReverse       = true,

    8                     RepeatCount       = int.MaxValue,

    9                     Apply             = (v) => item.Color = v,

   10                 };

   11 

   12                 colorAnim.Start();

In this example, we’re animating the color of ‘item’ from its initial color to Firebrick over 2 seconds.  This is similar to before except this time three new properties are introduced. ProgressTransform is a delegate that transforms the animation progress so that you can control the pacing of the animation.  In this case we’re using a predefined ProgressTransform called Snake (which looks like half a cosine wave).  AutoReverse tells the animation system that once the animation reaches the To value, it should head back to the From value.  RepeatCount tells the animation system how many times to do this before the animation is complete.  In this case, we’re more or less saying ‘do it forever’.  The end result is that the color will oscillate smoothly between its initial color & Firebrick.

 

That’s all for now folks.  If you want to see these animations in action, the zip below contains an XNA 3.1 project with the ZoomEngine.Animation library & a sample app.  Feel free to use this animation system in your own game and/or modify it in any way.  If you make something cool, send me a link (REMOVETHISbrandf AT microsoftREMOVETHIS.com)

Posted by brandf | 0 Comments
Filed under: , ,

A new adventure

This blog hasn't been very active since I created it, but that's about to change.

I recently moved from teams from WPF to the XNA Game Studio Framework team within Microsoft.  That means this blog is now going to focus on XNA & Game Development.

Here's a short list of topics I plan to write about. Leave a comment if you have suggestions.

1) Animation in games
2) Game Physics concepts & techniques
3) HLSL Effects
4) Game Engine design ideas
5) Random posts about projects I'm working on.
6) Future XNA features (once public)

Posted by brandf | 0 Comments
Filed under:

Beware of local scoping in .NET

Last week Jordan Parker and I were looking at a chunk of code that was evidently leaking memory.  What we discovered wasn't obvious at first so I thought I'd share it with the world.  The code looked something like this:

    void BackgroundThreadProc()
    {
        while (true)
        {
            _waitEvent.WaitOne();

            while (!WorkQueueEmpty())
            {
                WorkItem item = DequeueWorkItem();
                ProcessWorkItem(item);
            }
        }
    }

The idea is that we have a thread that waits to get signaled then flushes a queue of work items and goes back to waiting.  What could go wrong?  Imagine the following sequence of events:

  1. a work item is queued and the background thread is signaled.
  2. the background thread processes the work item and goes back to waiting for a signal.
  3. a long time elapses before another work item is queued.

The problem we ran into is that after 2. the local variable "item" was still in scope.  From the C# perspective, you may think that "item" is out of scope while we're blocked in "WaitOne", however this is merely a language notion.  Local variables in .NET are scoped to methods, which means "item" is a GC root whenever we're executing this method.  This caused the most recently processes WorkItem not to be garbage collected, and that caused anything the WorkItem referenced not to be collected and so on.

We can see this by looking at the IL:

.method private hidebysig instance void BackgroundThreadProc() cil managed

{

.maxstack 2

.locals init (

[0] class WorkerThingy/WorkItem item)

L_0000: ldarg.0

L_0001: ldfld class [mscorlib]System.Threading.AutoResetEvent WorkerThingy::_waitEvent

L_0006: callvirt instance bool [mscorlib]System.Threading.WaitHandle::WaitOne()

L_000b: pop

L_000c: br.s L_001c

L_000e: ldarg.0

L_000f: call instance class WorkerThingy/WorkItem WorkerThingy::DequeueWorkItem()

L_0014: stloc.0

L_0015: ldarg.0

L_0016: ldloc.0

L_0017: call instance void WorkerThingy::ProcessWorkItem(class WorkerThingy/WorkItem)

L_001c: ldarg.0

L_001d: call instance bool WorkerThingy::WorkQueueEmpty()

L_0022: brfalse.s L_000e

L_0024: br.s L_0000

}

Notice that IL declares the locals near the top of the method body.  As far as the CLR is concerned 'item' IS in scope while we're waiting to get signaled.  This is something to keep in mind if you find yourself writing a method that never exits.

Posted by brandf | 1 Comments
Filed under: , , ,

Fun With Animation Part 1 - CompositionTarget.Rendering

image

Rich runtime support for animation is a key component of WPF and a lot can be said about it.  That is why I've started this multi part series of posts on the topic of having fun with WPF animations. 

Typically application animations are used as subtle visual cues (think blinking caret) or not-so-subtle transitions (think Flip3D).  Anyone how has played with the iPhone knows that a little animation can go a long way to making the difference between a boring app and something new and exciting.

In this series you'll learn how use animations in WPF to meet your applications needs, and hopefully I'll get you thinking about how to use animations to enhance the users experience.  Each post in this series will focus on a small part of WPF animation story, starting with today's topic: CompositionTarget.Rendering.

I decided to start with the Rendering event because I think it's the most familiar way to do animation for people coming from a Flash background, and because it's an easy way to dig into the basic concepts of animation before we dig into Timelines, Clocks, Storyboards, and the rest of WPF's animation classes.

Hooking the CompositionTarget.Rendering event will get you inside WPF's rendering loop.  This event is fired once each time WPF decides to render a frame.  Furthermore, and this is important for people trying to save battery life, hooking this event _causes_ WPF to continue rendering frames.  This is why it's important to only hook this event while you're animating, and remove your event handler when you're done.

Inside the event handler you have complete freedom to do whatever you want to any object.  In other words, hooking CompositionTarget.Rendering is very much a "do it yourself" animation system.  Later we'll learn about the "let WPF do it for me" style animation system, but for now we'll learn to manually animate things because it's good to know what's going on under the covers.  Besides, there are times when the Rendering event is the best choice, such as when you want to animate something based interdependencies between multiple objects (as you'll see below) or if you just want to control an animation in a procedural way such as a bouncing ball.

The term "Animation" simply means that something is changing over time.  It's most commonly associated with changing motion over time (movement), but in WPF you can animate almost anything.  In this posts sample we'll create a simple procedural motion animation which tells an element to follow or avoid another element.  This creates interesting motion patterns based on who's following/avoiding who.

The first step is to hook the Rendering event:

            CompositionTarget.Rendering += DancingChildren;

Next we need to create the elements to animate and define which elements to follow/avoid.  I'll use XAML to define the elements (in this case various Shapes) and I'll use the Tag property to define who to follow and who to avoid.  An attached property would also work for this purpose, but we'll keep it simple for now.

<Window x:Class="RenderingEventDemo.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300"
    >
  <Canvas>
    <!-- the format of Tag should be "element_to_follow;element_to_avoid" -->
    <Rectangle Fill="Red" Stroke="Black" StrokeThickness="3" Width="20" Height="20" 
               Name="Square" Canvas.Left="200" Canvas.Top="80" Tag="Rectangle;Squircle"/>
    <Rectangle Fill="Pink" Stroke="Black" StrokeThickness="3" Width="40" Height="20" 
               Name="Rectangle" Canvas.Left="80" Canvas.Top="300" Tag="Circle;Square"/>
    <Ellipse   Fill="Green" Stroke="Black" StrokeThickness="3" Width="20" Height="20" 
               Name="Circle" Canvas.Left="0" Canvas.Top="0" Tag="Ellipse;Rectangle"/>
    <Ellipse   Fill="LightGreen" Stroke="Black" StrokeThickness="3" Width="40" Height="20" 
               Name="Ellipse" Canvas.Left="0" Canvas.Top="200" Tag="Squircle;Circle"/>
    <Rectangle Fill="Blue" Stroke="Black" StrokeThickness="3" Width="20" Height="20" RadiusX="7" RadiusY="7" 
               Name="Squircle" Canvas.Left="30" Canvas.Top="80" Tag="Square;Ellipse"/>
  </Canvas>
</Window>

Next we'll need to change the location of the elements in our Rendering event handler.  This can be done in a number of ways, but I've chose to use the Canvas.Top & Canvas.Left attached properties.

        private void DancingChildren(object sender, EventArgs e)
        {
            Canvas root = this.Content as Canvas;
            Point center = new Point(this.ActualWidth / 2.0, this.ActualHeight / 2.0);
            foreach (FrameworkElement child in root.Children)
            {
                string[] tag = ((string)child.Tag).Split(';');
                Point follow = GetLocation((FrameworkElement)FindName(tag[0]));
                Point avoid = GetLocation((FrameworkElement)FindName(tag[1]));
                Point me = GetLocation(child);

                // impulse's tweaked to come close to an orbit around the center
                Vector attract = (follow - me) * 0.1;
                Vector repel = (me - avoid) * 0.1555;
                Vector toCenter = (center - me) * 0.099;

                SetLocation(child, me + attract + repel + toCenter);
            }
        }

        private void SetLocation(FrameworkElement child, Point point)
        {
            Canvas.SetLeft(child, point.X);
            Canvas.SetTop(child, point.Y);
        }

        private Point GetLocation(FrameworkElement frameworkElement)
        {
            return new Point(Canvas.GetLeft(frameworkElement), Canvas.GetTop(frameworkElement));
        }

As you can see we're incrementally moving all elements in the direction of the center & in the direction of the follow element & in the direction away from the avoid element.  The relative strength of each term is tweaked to put the elements into an orbit, but you can modify it to converge/diverge.  Changing the follow/avoid Tags also changes the movement behavior in interesting ways.

To see it in action you can run the attached project.

The astute reader may notice a major shortcoming with the sample I've shown.  Is the motion frame-rate independent?  No.  In the example I've shown the motion is dependent on how fast WPF decides to render.  On Vista this is typically clamped to the monitors refresh rate, so on my system it's 75Hz.  On a system with a refresh rate of 60Hz this animation would be slower.  It's usually a good idea to avoid being frame-rate dependent while animating, so I'll talk about strategies for doing this in the next post in this series.

The birth of a new blog.

Hello world.

Yes, another blog has just been born.  I feel obligated to say a bit about what this blog is going to be about, so here it goes.

I'm a developer at Microsoft on the WPF team, so much of the content here will relate to WPF.  On the other hand, I have broad interests so I want this blog to be a place where I can talk about software trends, languages, debugging, graphics, patterns, and just about anything else I find interesting in the tech world.

In future posts, I'll talk a little bit more about myself and what exactly I do on the WPF team.  I want to keep this post short so you'll have to stay tuned for that.

Posted by brandf | 1 Comments
Filed under: ,
 
Page view tracker