Creating Killer Animations in Code - Page 4
       by kirupa  |  17 October 2009

In the previous page, you added some code and got your circle moving when you previewed it. Now comes the really fun part - learning why the various components work the way they do.

Birds Eye View of How Things Work
Before diving into the code, I think it is helpful to look at the bigger picture and how everything works. An animation is nothing more than something changing over a period of time. That something could be a whole host of things, but for this example (and many others), something refers to properties.

Over a period of time, some property changes, and this property change is what we notice. In our example, what properties are changing? Looking at what our animation is doing. It is moving the circle in a circular fashion, and the properties that are changing seem to be horizontal position and the vertical position of the circle:

There are basically two things we are doing in our code:

  1. Setting the properties representing the horizontal and vertical position.

  2. Changing the properties at a given time using some sort of a timer-like mechanism.

At each tick of the clock, we change our properties gradually to give you the illustion of smooth movement. That is, of course, easier said than done. The preceding sentence is what I converted into all the C# code that you copied and pasted earlier. Don't let the volume of the code scare you though, for in the next section, we'll try to make sense of it all.

Looking at the Code
Ok, now that you have a conceptual understanding of what programmatic animations do - change properties over a period of time, let's see how all of that looks translated into code. I'm going to be starting at the top of BlueCircle.xaml.cs and move down.

The first handful of lines are just declaring variables:

private static Random randomMain = new Random();
 
private double angle;
private double speed;
 
private double xPos;
private double yPos;

The only thing that I will call out is that our randomMain variable is declared using the static modifier. The reason is that I want to persist only a single Random object throughout this application's life. This has to do with how random numbers are initialized in .NET, but I will delve further into random numbers in a different article sometime in the future.


public BlueCircle()
{
// Required to initialize variables
InitializeComponent();
 
this.Loaded += new RoutedEventHandler(CircleLoaded);
}

Next up is our BlueCircle constructor. If you are not familiar with what a constructor actually is, I'm going to refer you to my earlier tutorial on Classes. In a nutshell, it is basically the gateway to your code that is provided for you by default.

I added one line to our constructor, and that line is the non-grayed out one you see above. I am associating our UserControl's Loaded event with an event handler called CircleLoaded. Translated into English, when my circle usercontrol loads, I want to the CircleLoaded function to be called.


Speaking of CircleLoaded...

void CircleLoaded(object sender, RoutedEventArgs e)
{
xPos = Canvas.GetLeft(this);
yPos = Canvas.GetTop(this);
 
speed = .01 + randomMain.NextDouble();
 
if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this) == false)
{
CompositionTarget.Rendering += new EventHandler(AnimateCircle);
}
}

...let's look at it next. The CircleLoaded method, like I mentioned earlier, gets called when the Loaded event is fired. The first two variables initialize our horizontal and vertical positions that we declared earlier as xPos and yPos:

xPos = Canvas.GetLeft(this);
yPos = Canvas.GetTop(this);

I am getting the x and y positions of this user control by using the Canvas.GetLeft and Canvas.GetTop properties. This is the closest thing to a clean syntax you get in C# for getting an element's position

In the next line, I set the speed of our movement:

speed = .01 + randomMain.NextDouble();

Notice that our static randomMain variable is used to set a really small random number. As you will see shortly, there is a reason why the number is as small as it is.

The next statement block is interesting:

if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this) == false)
{
CompositionTarget.Rendering += new EventHandler(AnimateCircle);
}

This if statement has no bearing on what you see when you test your appllication. This is to ensure that the code I am going to talk about next does not run inside Expression Blend. I will describe the cool feature about this at a later time.

Ok, we have one more line left to describe, and I am going to describe in the next page - that's how important that line is.

Onwards to the next page!


1 | 2 | 3 | 4 | 5




SUPPORTERS:

kirupa.com's fast and reliable hosting provided by Media Temple.