Posts Tagged with TranslateTransform

Silverlight Circular Collision Animation

Building on the sample I created on Circular Motion, in this example I add a concept of collision.  In physics, deflection is the event that occurs where an object collides and bounces off of another surface.  In my example, two spheres collide at a given X/Y causing each ball to reverse direction and maintains its current speed and angle.

Just as in my previous example I use a single DispatcherTimer and a generic collection of UserConrols. To keep track of the direction that each ball is traveling I added a boolean property to my “Ball” user control to determine if it was rotating clockwise.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
void _timer_Tick(object sender, EventArgs e)
{
    foreach (Ball ball in _balls)
    {
        double x = 0.0
        double y = 0.0
        double angle = ball.Rotate.Angle
 
        CalculatePosition(ball.Clockwise, ref x, ref y, ref angle, 1)
        //update the position of the ball
        ball.Rotate.Angle = angle
        ball.Translate.X = x
        ball.Translate.Y = y
 
        //check to see if a collision has occured
        if (ball.CollisionType == Ball.CollisionTypes.Deflect)
        {
            foreach (Ball ball2 in _balls)
            {
                if (!ball.Equals(ball2))
                {
                    double b2X = 0.0
                    double b2Y = 0.0
                    double b2A = ball2.Rotate.Angle
                    //if we wait until the two balls are at the same X/Y then the balls
                    //will have overlapped.  Instead, predict by looking 5 degrees ahead 
                    //then switching direction.
                    CalculatePosition(ball2.Clockwise, ref b2X, ref b2Y, ref b2A, 5)
                    if (Math.Ceiling(x).Equals(Math.Ceiling(b2X))
                        &amp&amp Math.Ceiling(y).Equals(Math.Ceiling(b2Y)))
                    {
                        ball.Clockwise = !ball.Clockwise
                        ball2.Clockwise = !ball2.Clockwise
                        //ball.sound.Position = TimeSpan.FromMilliseconds(0)
                        //ball.sound.Play()
                        break
                    }
                }
            }
        }
    }
}

As you can see in the code above, I am doing a quick check to see if my rotating ball is defined to deflect upon collision. In this example, this is the only type of collision supported. In the future, I might add things like exploding on impact or magnetism upon the collision.

The first step in the circular rotation is to move each ball to its new X/Y position. Once moved, I check to see if any other balls overlap its current X/Y location. To make the collision more realistic (no overlap), I predict where each additional ball will exist 5 degrees forward of its current angle. This allows me to simulate the ball just touching each other before reversing directions.

Code: CircularCollision.zip

Silverlight Circular Motion Animation

In this sample I demonstrate how to take a series of UserControls (Simple ellipses) and rotate each in a counter-clockwise circular motion.

The first step in the process is to define a user control and expose both the TranslateTransform and RotateTransform from the TransformGroup object.  This allows us to rotate and move each user control on a specified tick (DispatcherTimer tick).  The timer is controlled by the main page.xaml.

In this example, I start with a single “ball”, begin rotating it, and every second add an additional ball to the animation.  Instead of having each user control have its own animation, I have chosen to use a single DispatcherTimer that iterates over a generic collection of UserControls, to generate the circular motion

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void Page_Loaded(object sender, RoutedEventArgs e)
{
    _centerX = this.Width/2
    _centerY = this.Height / 2
    _timerAnimation.Interval = TimeSpan.FromMilliseconds(20)
    _timerAnimation.Tick += new EventHandler(_timer_Tick)
 
    _timerInserter.Interval = TimeSpan.FromSeconds(1)
    _timerInserter.Tick += new EventHandler(_timer2_Tick)
 
    PlaceBall("Bo")
 
    _timerAnimation.Start()
    _timerInserter.Start()
}

In this handler I determine the center of my circle, place the first control, and define two DispatcherTimers, one for the animation, and one for inserting additional controls into the main Grid. Since the speed of rotation is consistent for each “ball”, I am able to use a single timer which iterates over a generic collection of UserControls. Each time the Animation timer fires, I will call the following method.

1
2
3
4
5
6
7
8
9
10
11
12
void _timer_Tick(object sender, EventArgs e)
{
    foreach(KeyValuePair<string ,BALL> ball in _balls)
    {
        ball.Value.Rotate.Angle -= 5
        ball.Value.Rotate.Angle %= 360
        // Transform angle degrees to radian value
        double radians = ((ball.Value.Rotate.Angle / 180) * Math.PI)
        ball.Value.Translate.X = _centerX + Math.Cos(radians) * _radius
        ball.Value.Translate.Y = _centerY + Math.Sin(radians) * _radius
    }
}

The math in this method is pretty basic, on each tick I rotate the ball between 1 and 360 degrees. The angle I am looking for is the remainder of the angle of my rotation from 360 degrees. To calculate this, I apply the modulus assignment operator to my new angle. To determine the appropriate X and Y position I transform my angle into Radians and apply a bit of trigonometry to calculate X/Y based on the sin and cosine of the radian. Thanks again to Paul Ortchanian flash site, reflektions for a Flash sample I could translate into Silverlight.

Code: CircularMotion.zip

Silverlight how to: Procedural Animation

Whenever possible developers should encourage designers to maintain all of their Silverlight storyboards within XAML. This allows the designers the optimum environment to use a tool like Blend to tweak the animation timing, easing and any relevant Key Splines. That said, there are situations where a developer may create a UserControl that requires full control over the format of the animation. Defining this storyboard procedurally, allows the developer a more consistent level of control and allows an easier approach to manipulating properties within this storyboard.

The following will show a simple example of how one could include a “DoubleAnimationUsingKeyFrames” that allows the TranslateTransform’s “X” property to be manipulated each time the animation is played.

The first step in defining our animating UserControl is to attach a “Loaded” event handler within our constructor. This allows us to have the XAML parsed by the UserControls base class, yet inject a procedural storyboard into the UserControls resources.

1
2
3
4
5
public Box()
{
  InitializeComponent()
  this.Loaded += new RoutedEventHandler(Page_Loaded)
}

Our storyboard will include a “DoubleAnimationUsingKeyFrames”, “SplineDoubleKeyFrame” with a corresponding “KeySpline”. I have chosen to refactor this logic into a method. In the event that we wanted to manipulate both the “X” and the “Y” TranslateTransform property, this method could be called twice passing both “X” and “Y” as the last argument.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private static SplineDoubleKeyFrame CreateDoubleAnimation(ref Storyboard sb,
   TranslateTransform translation, string property)
{
    DoubleAnimationUsingKeyFrames da = new DoubleAnimationUsingKeyFrames()
    da.SetValue(NameProperty, string.Concat("da_", property))
 
    SplineDoubleKeyFrame sdkf = new SplineDoubleKeyFrame()
    sdkf.SetValue(NameProperty, string.Concat("sdkf_",property))
 
    sdkf.Value = 0
    sdkf.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(0.25))
 
    //define the KeySpline
    KeySpline ksX = new KeySpline()
    ksX.ControlPoint1 = new Point(1.0, 0.25)
    ksX.ControlPoint2 = new Point(0.75, 1.0)
    sdkf.KeySpline = ksX
 
    //add the SplineDoubleKeyFrame to the DoubleAnimationUsingKeyFrames
    da.KeyFrames.Add(sdkf)
 
    //define which TranslateTransform property will be targeted by the DoubleAnimation
    Storyboard.SetTarget(da, translation)
    Storyboard.SetTargetProperty(da, property)
    sb.Children.Add(da)
    return sdkf
}

Within our Page_Loaded handler we define the transformation group for this control, call our helper function and insert the storyboard into the UserControls grid (LayoutRoot) resource collection. In this example, we are only manipulating the 2D, X/Y coordinate system so we only need to include the “TranslateTransform” within the transform group. If Scale was being translated as well, we would include a “ScaleTransform” object within the group.

1
2
3
4
5
6
7
8
9
10
11
12
void Page_Loaded(object sender, RoutedEventArgs e)
{
    //define the Render Transformation for this control
    TranslateTransform translation = new TranslateTransform()
    TransformGroup transforms = new TransformGroup()
    transforms.Children.Add(translation)
    this.RenderTransform = transforms
 
    _sdkfX = CreateDoubleAnimation(ref _sb, translation, "X")
 
    this.LayoutRoot.Resources.Add("playerAnimation", _sb)
}

Lastly, I created a public method in the UserControl that sets the “X” and starts the animation. This method can be called repeatedly from the location that is instantiating this UserControl.

1
2
3
4
5
6
public bool Animate(int x)
{
    _sdkfX.SetValue(SplineDoubleKeyFrame.ValueProperty, x)
    _sb.Begin()
    return true
}

Code: Animation.zip