Posts Tagged with code

Loading images in Silverlight 2

Reading through the Silverlight.net forum I still see a ton of people struggling with how to load an image procedurally. I thought it would be beneficial to included a quick sample of four different ways you can set the Image.Source property within Silverlight 2.

image_loading1




Image 1 - Resource Loaded via XAML - The easiest and most common way to load an image is to include the image in your project and set its "Build Action" to Resource. This will embedded the image within the primary assembly which gets packaged in your projects XAP file. Here is what that assembly looks like if you explore it with Reflector.

image_loading3


To reference this embedded resource within xaml, you can set the source attribute equal to the following

<Image Source="ImageSource;component/1.jpg"…>

Image 2 - Resource Loaded procedurally - In the event that you need to swap or load an images source procedurally, you can simply load up a BitmapImage via a relative URI and set the Image.Source equal to this object.

//Image 2 - Loaded via bitmap image data
// - Build Action=Resource
// - Copy to Output Directory = Do Not Copy
BitmapImage bmpImg2 = new BitmapImage()
Uri uri2 = new Uri(&quot2.jpg&quot, UriKind.Relative)
bmpImg2.UriSource = uri2
image2.Source = bmpImg2

Image 3 - Build Action = Content – If you do not desire to embed an image within your assembly, you can set its build action to “Content” and that image will be packaged within the XAP.

XAP File


//Image 3 - Load image that is included in the XAP file
// - Build action = Content
// - Copy to Output Directory = Do Not Copy
BitmapImage bmpImg3 = new BitmapImage()
Uri uri3 = new Uri(&quot/3.jpg&quot, UriKind.Relative)
bmpImg3.UriSource = uri3
image3.Source = bmpImg3

(Note: The image file name in the URI is proceeded with a front slash (/).  This is required to indicate that the image is relative to the location of the assembly.)


Image 4 - Build Action = None / Copy to Output Directory = Copy always - In the instance that you don’t want the image to be downloaded locally (packaged in XAP), you can set the “Build Action” equal to “None” and set the “Copy to Output Directory” equal to “Copy always”.  /bin directory


Using the “TestPage.html” page which is automatically generated in your projects “bin” directory you can reference the image location relatively, just as you did in sample 3.

//Image 4 - Load image that is located at some relative url
// - Build action = None
// - Copy to Output Directory = Copy always 
//      (Note: I had to manually copy the image to 
//       my web projects ClientBin directory)
BitmapImage bmpImg4 = new BitmapImage()
Uri uri4 = new Uri(&quot/4.jpg&quot, UriKind.Relative)
bmpImg4.UriSource = uri4
image4.Source = bmpImg4

Code: ImageSource.zip

Silverlight 2 Video Player pushed to CodePlex

Yesterday Tim Heuer made a great suggestion that we submit our collaboration on a  Silverlight 2 Video Player as Open Source to CodePlex. You can now find the latest source at http://www.codeplex.com/sl2videoplayer.  As we find any “undocumented features” or add new and exciting ehancments we will push these up to CodePlex.

Silverlight 2 – Media Player with Marker support

Back in April I created a very simple Video Player in Silverlight 2 Beta 1 which Tim Heuer took to a whole new level. In his first pass he added dynamic resizing and initParams to load the video source. Then back a few weeks ago Tim brought it up to speed for Beta 2 and integrated the "VisualStateManager" to get the ToggleButton to function correctly. I love how it turned out.

One thing that I really wanted to include in my first version was control for TimelineMarkers. Unfortunately in Beta 1 I had some issues with dynamic markers, and decided to hold off until Beta 2 was released. Microsoft Expression Encoder 2 is a great tool and makes it very easy to insert markers that fire events during video playback. Markers are very simple, they define a TimeSpan of when to fire the "MarkerReached" event, and define some text that describes the marker.   In my example I will use this text as the copy for my Marker Popup.  Here is how I chose to visualize my markers in the video player.

videoplayer_c2

To achieve this effect, I created a custom UserControl called "Marker.xaml". This control contains a single animation which will fade in the text, and fade it out again after a predefined amount of time.  The control is comprised of a TextBlock and a “Arrow” path that can be moved left and right within the second row of a Grid control.  This gives me the ability to control where the Arrow visualizes in relation to my Timeline Slider control.

Based on the number of markers encoded in the video an equal number of markers will be placed in the “MediaControl”.  There position on the slider time line is determined by calculating the following:

videoplayer_c3


The position is not absolute, but close enough to where the “Thumb” in the slider control will exist at that moment the marker should popup.   Once I have placed a marker into the appropriate Grid on my MediaControl I store it in a generic Dictionary keyed off of the time it should be displayed. This allows me to very quickly find the UserControl when the Media.MarkerReached event fires or the player goes into fullscreen mode.   In the event that the user wants to play the video in fullscreen, I must reposition my markers relative to the new ActualWidth of the  sliderTimeline. 

videoplayer_c4


Here is how it all turned out. 

Code: VideoPlayerMarkers.zip

Silverlight 2 MVC Game Framework

Last week I presented a session at DesertCodeCamp 2008 on Developing Casual Games with Silverlight 2. Excluding some technical difficulties, getting my MacBook to connect to dual projectors, the presentation went well. There is certainly interest in the community to begin using Silverlight as a casual gaming platform.

The goal of this presentation was to create a more “developer” focused exploration into a development architecture one could use for building a casual game. In this example, one which leverages pixel-based movement. As with everything in development, there is no real right or wrong architecture, just proven patterns, that have proven scalability, flexibility and efficiency.

Concept

Build a simple game where a player has to move around a box and avoid a series of randomly moving spheres. Each sphere can collide with both the bounds of the box, each other and the player. The player can only be collided with 5 times or the game is over. Player movement is controlled by hitting a combination of arrow keys which changes the vector angle of the players movement. The players speed is consistent, until that player collides with one of the spheres. The behavior of the collision will change based on the element being collided with..

Framework

Last fall Microsoft released its first version of the Model-View-Controller (MVC) framework for ASP.NET as a way to help developers implement this proven separation pattern into ASPX site design. If you have not got a chance to use I strongly recommend giving it a try.

VS 2008 SolutionAt a very high level MVC divides an application’s implementation into three components: models, views, and controller. This “separation” is used specifically as a way to improve a developers ability to decouple the presentation layer from the business logic. In game development, MVC is an excellent way to build a foundation which simplifies a developers ability to control state such as movement and collision detection. Unfortunately a formal MVC framework does not exist for Silverlight 2, but implementing the pattern is pretty simple. The image to left illustrates how I have implemented the MCV pattern in my example project.

Exploring further you will see that I do not consider “page.xaml” a view. This is intentional. page.xaml is simply a way to get my controller instantiated. All game elements will be inserted into my “Shell.xaml” view by my controller, and this UserControl will be inserted into the page’s LayoutRoot after the page’s xaml has been loaded. My controller will get a reference to this root UIElement via constructor dependency injection, a common approach seen in MVC implementations. Here is the code found within page.xaml.cs.


public partial class Page : UserControl
{
    private Controllers.Controller _controller
    private Views.Shell _shell = new Views.Shell()
    public Views.Shell Shell
    {
        get { return _shell }
        set { _shell = value }
    }
 
    public Page()
    {
        InitializeComponent()
        this.Loaded += new RoutedEventHandler(Page_Loaded)
    }
 
    void Page_Loaded(object sender, RoutedEventArgs e)
    {
        LayoutRoot.Children.Add(_shell)
        _controller = new Controllers.Controller(this)
        _controller.Initialize()
    }
}

Controller

In this game I have a single controller which acts as the central nervous system of my game. It controls the following:

  • Primary game timer (tick)
    • Moves Player, Balls and checks for Collisions
  • Inserts the appropriate dialogs and listens to events from each
    • Start, End, Next Level
  • Listening for events from my primary model
    • Collision, NextLevel, GameOver and StopMovement
  • Captures the approriate keyboard inputs
    • Left, Right, Up, Down, Left-Up, Left-Down, Right-Up, Right-Down

Game Model

The controller instantiates and holds a reference to my primary game model which will maintain the games state and expose any methods used to interact with the “Player” and “Hazards” [ball]). The model is the single places that knows how to start a level, insert the player and place each of the balls into a level. When events occur like the player collides with a ball, the model fires an event to the controller indicating what transpired. The controller decides what this means visually to the game play (updates the “Shell” to indicate a new Hit count). The model maintains state so it will be responsible for deciding when the game is over. A game is over when either time has expired (15 seconds) or five collisions have occurred. As with a collision, the model will fire an event to the controller when the game is over.

Behaviors

Part of building this sample was to build upon some of the previous work I have done on spherical collisions. Is previous posts, I have shown how to react to both an elastic and inelastic collision. In this example I refer to elastic behavior as “Deflect” and inelastic as “Bump”. The idea is that if I build an object oriented methodology of defining collision behavior, one based on inheritance, I can expand the types of hazards as I develop new behaviors. For example, the next behavior I intend to develop is one which hazards chases the player, when the hazard gets within a specified proximity of the player.

Here is the game and source.

Code: CodeCampGame.zip

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

Silverlight 3D flip animation

Up until now I have not had an opportunity to create any Silverlight procedural animations that were more complicated then positioning an object with some simple easing. I thought it would be fun to attempt to duplicate one of the transitions used on the iPhone. While making a phone call, if you choose to display the keypad there is a cool 3D flip that occurs. Here is a quick video of the transition. [[VIDEO]] In hopes not to reinvent the wheel, I embarked on an endless search of the Internet for anything resembling a flip. After some quality time on Google, I stumbled upon a great Flash site called reflektions by Paul Ortchanian. This site has a ton of Flash examples that highlight 2D and 3D effects done in flash. Those of us new to interactive development can learn a ton from the techniques Flash and Flex developers have used for years. To get started I created a simple page that contained two Grid controls, one for the front of the flip and one for the back. Both were placed inside of a single canvas named “screens”.

The guts of this effect has been encapsulated in a method called “AnimateFlip”. The result of this method is a DobuleAnimation with approximately 48 descreate keys frames.

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
private TimeSpan AnimateFlip(Storyboard sb, ScaleTransform scale, 
out TimeSpan tsLastFrame)
{
    double speed = 4
    double flipRotation = 0
    double flipped = 2
    tsLastFrame = new TimeSpan()
    TimeSpan tsSideFlipped = new TimeSpan()
 
    int frames = 1
    DoubleAnimationUsingKeyFrames daX = 
	new DoubleAnimationUsingKeyFrames()
    tsLastFrame = new TimeSpan()
    while (flipRotation != flipped * 180)
    {
        flipRotation += speed
        double flipRadian = flipRotation * (Math.PI / 180)
        double size = Math.Cos(flipRadian)
        double scalar = (1 / (1 / size))
 
        DiscreteDoubleKeyFrame ddkfX = new DiscreteDoubleKeyFrame()
        ddkfX.Value = (size * scalar) 
 
        tsLastFrame = TimeSpan.FromMilliseconds(frames * 7)
 
        //the first time we flip to negative capture the 
	//tsLastFrame so we know when we will need to
        //visualize the flip side
        flipped = (size < 0) ? +1 : +0
        if (flipped == 1 && tsSideFlipped.Ticks == 0)
        {
            tsSideFlipped = tsLastFrame
        }
 
        ddkfX.KeyTime = KeyTime.FromTimeSpan(tsLastFrame)
 
        //add the DiscreteDoubleKeyFrame to the 
	//DoubleAnimationUsingKeyFrames
        daX.KeyFrames.Add(ddkfX)
 
        flipRotation %= 360
        frames++
    }
 
    Storyboard.SetTarget(daX, scale)
    Storyboard.SetTargetProperty(daX, "ScaleX")
    sb.Children.Add(daX)
 
    VisualizeSide(sb, tsSideFlipped, 0, TimeSpan.FromMilliseconds
		((tsSideFlipped.Milliseconds + 100)), 
		back.Opacity, this.back)
    VisualizeSide(sb, TimeSpan.FromMilliseconds((
		tsSideFlipped.Milliseconds - 100)), front.Opacity, 
		tsSideFlipped, 0, this.front)
    back.Opacity = 0
    return tsLastFrame
}

At the very bottom of the above method their is two calls to “VisualizeSide”. This method is responsible for visualizing the second side when the screen has rotated 180 degrees (Flipped).

My animation is by no means exact, but a pretty good first attempt. If you watch the video very slowly you might notice that on the iPhones rotation it looks like it rotates in perspective. I would love to add this, but am at a lost

Code: ScreenFlip.zip

Silverlight how-to: Video Player

In my ongoing quest to work with Silverlight 2 I embarked on building my own video player using the standard MediaElement and a few of the new System Controls (ToggleButon, Slider and Button). My goal was to build a video player using no custom user controls, but instead leveraging controls styles and templates.  Here is the Video Player I ended up developing.

As you can see from my example, I was able to get a pretty clean look and feel with minimal artistic skills required.   The way my player is constructed, I have opted to encapsulate the controls for playing video into its own UserControl.  This allowed me to have a single place responsible for managing playback while allowing the main xaml page to control how the MediaElement is presented.  To give the controller access to a specific MediaElement, I pass it to my controller via a public property.

Most of the customization techniques I used are pretty well documented on MSDN.  Nonetheless, mastering controls styles was definitely a challenge. For those unfamiliar with control styles, here is an example of the xaml I used to "skin" my mute button.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<style x:key="speakerStyle" targettype="Button">
  <setter property="Template">
    <setter.value>
      <controltemplate targettype="Button">
        <grid x:name="RootElement">
          <path stretch="Fill" fill="#FFFFFFFF" data="F1 M 23.1457,
            26.5056L 23.1457,33.8944l 25.7913,33.8944l 28.8235,37.4722l 
            30.5346,37.4722l 30.5665,23.0833l 28.8995,23.0833l 25.8679,
            26.5056l 23.1457,26.5056 z " Width="7.42080116271973" 
            height="14.3889999389648"/>
        </grid>
      </controltemplate>
    </setter.value>
  </setter>
</style>

This is about as simple a skin as one can get. If I were doing this for a real client I would have certainly choose to give my button multiple states (MouseOver, Down, ect) In Silverlight 2 control states are achieved by including specific named Storyboards in your ControlTemplate resource dictionary. Each control provides a different set of pre defined states. Here is a list of the states available for a ToggleButton.

  • Checked State - The normal checked state of the control.
  • Indeterminate State - The normal indeterminate state of the control.
  • Normal State - The normal unchecked state of the control.
  • MouseOver Checked State - The state that is triggered when the mouse pointer is positioned over the checked control.
  • MouseOver Indeterminate State - The state that is triggered when the mouse pointer is positioned over the indeterminate control.
  • MouseOver Unchecked State - The state that is triggered when the mouse pointer is positioned over the unchecked control.
  • Pressed Checked State - The state that is triggered when the checked control is pressed.
  • Pressed Indeterminate State - The state that is triggered when the indeterminate control is pressed.
  • Pressed Unchecked State - The state that is triggered when the unchecked control is pressed.
  • Disabled Checked State - The state that is triggered when the checked control is disabled.
  • Disabled Indeterminate State - The state that is triggered when the indeterminate control is disabled.
  • Disabled Unchecked State - The state that is triggered when the unchecked control is disabled.

In my example I use the ToggleButton to control playback of the video.  Instead of creating two buttons, one for play and one for pause, I  choose to use a ToggleButton to combine them into one.  I display a play symbol when the video is stopped or paused, and a pause symbol when the video is playing.  The ToggleButton functions just like a checkbox, clicking it once "check’s" it while clicking it again "uncheck’s" it.   The following  is a sample of one of the Storyboards I used in skinning my ToggleButton. This animation controls which elements are visualized when a users presses the ToggleButton in an previously checked state.

1
2
3
4
5
6
7
8
9
10
11
<storyboard x:key="Pressed Checked State">
   <doubleanimation duration="0:0:0.1" 
     storyboard.targetname="playSymbol" 
     storyboard.targetproperty="Opacity" to="0" />
   <doubleanimation duration="0:0:0.1" 
     storyboard.targetname="pauseSymbol" 
     storyboard.targetproperty="Opacity" to="1" />
   <doubleanimation duration="0:0:0.1" 
    storyboard.targetname="buttonPressed" 
    storyboard.targetproperty="Opacity" to="1" />
</storyboard>

In the code above, I am ensuring that the play symbol is hidden while I show both a pause symbol and an glow image used to show the button is being pressed.

As for procedural code, all of the heavy lifting is done in the mediaControl.xaml.cs codebehind file.  The majority of code is event handlers responding to user interactions (clicks, drags,etc) or a single DispatcherTimer monitoring progress in the video playback.  My  DispatcherTimer fires a tick every 50 milliseconds which update how much time has played and visualizes on a slider how much time remains.

Code: VideoPlayer.zip