Posts Tagged with 3D Flip

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 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