Archive for May, 2008

Spherical elastic and inelastic collisions in Silverlight

I recently took an interest in using some very basic physics within Silverlight 2. I took physics nearly 12 years ago and am certainly rusty, but thought it would be fun to simulate he effect two spheres have when they collide. Their are two types of collision; a perfectly elastic collision where there is no lose in kinetic energy and an inelastic collision where some or all of the kinetic energy is converted into internal energy.   In the example below I try to demonstrate both types of collision along with a form of inelastic collision I call magnetic where upon collision energy is transferred in the direction of the collision and the sphere attaches itself to the object it is colliding with.

I am pretty certain I am taking some liberties with accuracy of each collision, but nonetheless one can see the effect two spheres have on momentum.  Interestingly, if you allow the demo to run long enough most if not all of the balls will stop colliding. The first thing I needed to do to create my sample was to create a UserControl that would represent my sphere. Within this control I created a series of properties and two public Method: “Move()” and “Collision()”. Since each sphere will move through my container the same way, I can encapsulate this logic within the control itself. Here is that code.

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
public void Move(Rect bounds)
{
    //add the current vector to each X/Y 
    this.X += this.VX
    this.Y += this.VY
 
    //check to see if this sphere has collided with an adjacent wall
    //if so, then reverse its vector.  Since my bounding box is definable 
    //pass in a Rect struct
 
    //check the left and the right of the bound box
    if (this.X &lt bounds.X &amp&amp this.VX &lt 0)
        this.VX = -this.VX
 
    if(this.X &gt (bounds.Right-this.Distance) &amp&amp this.VX &gt 0)
        this.VX = -this.VX
 
    //check the top and the bottom
    if (this.Y &lt bounds.Y &amp&amp this.VY &lt 0)
        this.VY = -this.VY
 
    if(this.Y &gt (bounds.Bottom-this.Distance) &amp&amp this.VY &gt 0)
        this.VY = -this.VY
 
    //move this sphere to its new X,Y position
    _translate.X = this.X
    _translate.Y = this.Y
}

Since my container floats in the center of my Page.xaml I use a “Rect” struct to hold the X,Y, Width and Height of the UIElement that that will confine the spheres. I pass this “Rect” as an argument. Depending on the surface that the object is colliding with, I move the sphere and reverse the vector by either adding or subtracting itself from VX or VY. In addition to determining how itself moves, the sphere I also determines the effect of a collision. This method is pretty big, but is broken down into four sections. The first determines the time in which the two spheres collide where is the remaining determine the effect of each type of collision.

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
public bool Collision(Sphere s)
{
    // find the time when the two spheres really collide with each other.
    double dx = (this.X + this._radius) - (s.X + s.Radius)
    double dy = (this.Y + this._radius) - (s.Y + s.Radius)
 
    //calculate the distance between two balls 
    double distance = dx * dx + dy * dy
    double distanceSqrt = Math.Sqrt(distance)
 
    double dvx = this.VX - s.VX
    double dvy = this.VY - s.VY
 
    if (distanceSqrt &gt (this._radius + s.Radius))
        return false
    //There are two basic kinds of collisions, elastic and inelastic:
    //if an elastic collision occurs send both spheres rebounding backwards
    //with no loss in total kinetic energy.
 
    //Note: since both of our spheres have the same mass the only way to determine 
    //which type of collision will occur is to look at velocity.
    double collision = 0.0
    if (this.CollisionType == CollisionTypes.Elastic  
	s.CollisionType == CollisionTypes.Elastic)
    {
        collision = dvx * dx + dvy * dy
        if (collision &gt 0)
            return false
 
        collision /= distance
 
        double deltaVX = dx * collision
        double deltaVY = dy * collision
 
        //deflect this sphere
        this._vx -= deltaVX
        this._vy -= deltaVY
        //deflect the sphere that was part of the collision
        s.VX += deltaVX
        s.VY += deltaVY
    }
    //if a partial inelastic collision occurs the spheres collide and some 
    //kinetic energy is lost...both masses decelerate
    else if(this.CollisionType == CollisionTypes.Inelastic  
	s.CollisionType == CollisionTypes.Inelastic)
    {
        collision = dvx * dx + dvy * dy
        if (collision &gt 0)
            return false
 
        collision /= distance*2
 
        double deltaVX = dx * collision
        double deltaVY = dy * collision
 
        //deflect this sphere
        this._vx -= deltaVX
        this._vy -= deltaVY
        //deflect the sphere that was part of the collision
        s.VX += deltaVX
        s.VY += deltaVY
    }
    //if a magnetic collision occurs we would have a perfectly inelastic collision
    else if (this.CollisionType == CollisionTypes.Magnetic &amp&amp 
	s.CollisionType == CollisionTypes.Magnetic)
    {
        //the sphere causing the collision will continue its forward momentum 
        //attaching itself to the adjacent sphere
        s.VX = this.VX
        s.VY = this.VY
    }
    return true
}

Code: SphericalCollision.zip

Silverlight Flipping Tiles Animation

Back a few weeks ago I posted an example of how to create a 3D flip animation similar to the effect seen on an iPhone. Today I will build upon that procedural animation and simulate the flipping tile affect seen in the iTunes album art screen saver, available on a Mac.

In my example I have a total of 16 random tiles displayed from a collection of 42 different images. Any image not currently displayed is available to be randomly selected to replace an existing tile.  Here is how I achieve the effect. 

The project is comprised of a “Tile” UserControl , a class called “Media” and two generic lists (one to store references to the 16 tiles and one to store all 42 URI to the images).  The first step is to fill my page.xaml grid with 16 tiles.   Here is a snip of the code used to fill the grid.

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
private void BuildCollection()
{
    int row = -1
    int col = 0
    for (int i = 0 i &lt 42 i++)
    {
        Uri imageUri = new Uri(string.Format("Images/{0}.png", 
		(i+1).ToString()), UriKind.Relative)
        if (i &lt= 16)
        {
            Tile tile = new Tile()
            Media media =  new Media(imageUri, true)
            tile.Media = media
 
            if (col % 4 == 0)
            {
                row++
                col = 0
            }
            tile.SetValue(Grid.ColumnProperty, col.ToString())
            tile.SetValue(Grid.RowProperty, row.ToString())
            this.LayoutRoot.Children.Add(tile)
 
            col++
            _tiles.Add(tile)
            _images.Add(media)
 
        }
        else
            _images.Add(new Media(imageUri, false))
    }
}

For those of you just getting familiar with the “Grid” control you might not be aware that it supports implicitly specifying columns and rows. In this example I leverage this to ensure my tiles form a nice 4×4 grid.  

As you can see from the code, I have chosen to store only the URI to the image and not store the image itself. I had some difficulty storing a “BitmapImage” object in my collection and retrieving it consistently when I was ready to flip a tile. The URI seems less efficient, was reliable.

Now that I have built up my grid and two collections, I can use a DispacherTimer to randomly select a tile and randomly select an image to be used as the backside of the flip. He is how that code looks.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void _timer_Tick(object sender, EventArgs e)
{
    System.Random RandNum = new System.Random()
    int randomTile = RandNum.Next(16)
 
    bool match = false
    while(!match)
    {
        int randomImage = RandNum.Next(42)
        if(!_images[randomImage].Displayed)
        {
            _images[randomImage].Displayed = true
            _tiles[randomTile].Media.Displayed = false
            _tiles[randomTile].Flip(_images[randomImage])
            match=true
            break
        }
    }
}

As you can see I am using a boolean property in the “Media” object to determine if an image is already displayed. The second level of randomization is there to help ensures that I am giving each image equal chance of getting displayed.

If one were to examine the “Tile” UserControl, it looks almost exactly like the code I created for the 3D flip animation example. In  this situation instead of firing the flip based on a button click, I use the followings public method called from my main page.xaml DispatcherTimer tick.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public void Flip(Media media)
{
    this.Media = media
 
    if (_Front)
    {
        this.ImageBack.Source = new BitmapImage(_Media.ImageUri)
        _sb.Pause()
        _sb.AutoReverse = false
        _sb.Begin()
        _Front = false
    }
    else
    {
        this.ImageFront.Source = new BitmapImage(_Media.ImageUri)
        _sb.Pause()
        _sb.AutoReverse = true
        _sb.Seek(_tsLastFrame)
        _sb.Resume()
 
        _Front = true
    }
}

Code: LeopardSreenSaver.zip

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

RealNetworks plans spinoff of casual games business

I stumbled upon this news article on BussinessWekk.com last week and thought it was quite interesting that Real Networks would find the potential in casual gaming so optimistic that it would spin off its division into a seperate company. This move could certainly push Real Networks into the lead within the casual gaming space.

XNA Gamefest 2008

For those that might be interested, this year’s XNA Gamefest will be held at the Washington State Convention and Trade Center in downtown Seattle on July 22-23 2008. In previous years the conference has included presentations in the following tracks.

  • System Programming for Windows and Xbox 360
  • Graphics
  • Quality Assurance and Certification
  • Producer and Business Development
  • Audio
  • LIVE
  • XNA Game Studio
  • Games for Everyone
  • Visual Arts

I am not sure if all of these tracks will be presented in July, but I know for certain that they have decided to expand its focus and include a Casual Gaming track highlighting some of the cool new games done in Silverlight. When I know more information I will let everyone know.