Posts Tagged with Blend

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

Tunnel Trouble on Silverlight.net

For those of you who might not have seen our presentation at Mix, Terralever recently completed a second Silverlight game for Miniclip.com called Tunnel Trouble. This game is entirely written against the Silverlight 2 Beta 1 plugin. I am not sure that it has been spotlighted on there web site, but Microsoft has placed it on the home page of Silverlight.net. When you get a chance give it a play we are very happy with how it came out.

Silverlight how to: Frame-by-Frame Animation

For the past few weeks, Terralever has been developing our second game using the Silverlight framework. Our first, Zero Gravity was a great success and highlighted the power that Silverlight can bring to casual gaming development. For years, Terralever has been developing games in Flash and is very fortunate to have some incredible flash interactive developers.

One of the essential elements found in all interactive games is frame-by-frame animations. When a character moves across the screen that movement is a combination of repositioning the character as an element, combined with a sequence of character movements (the animation).

Now I don’t pretend to be a Flash developer, but what I have been told is that creating Frame-by-Frame animations in flash is very easy. You simply create a key frame and insert an object on to that frame. The combination of all key frames produces the animation sequence.

In Silverlight / Blend 2 December Preview creating this type of animation sequence is more difficult. Storyboards in Silverlight are independent of any canvases that will contain the individual animation sequences. Creating a key frame in Silverlight, does not generate a new canvas. In our first Silverlight game we achieved frame-by-frame animations by stacking a series of frames (canvases) and modifying the objects opacity property to appears as if we moved through the sequence. This technique was extremely difficult to work with in blend.

We figured there had to be a easier way. Instead of stacking the frames on top of themselves and using opacity, I decided to position them adjacent to each other and discreetly move the parent canvas from right to left. Think of it like an image strip when the first image starts at X=0 and each adjacent frame is positioned (X+FrameWidth). The result was the canvas shown in Figure 1.

framesequence.png



Once the frames are positioned in the correct sequence, I created a Canvas.Clip to clip the main canvas at position 0,0 with a width and height equal to the size of each frame. This clip will mask all of the adjacent frames when we play the animation.

The next step was to create the animation storyboard. For my “less than” creative animation I generated 8 frames, each with a very simple vector. My storyboard will require 1 key frames per frame of the sequence, plus one additional key frame to get back to the starting position. By default, Blend will “tween ” between each key frame. To achieve a discrete transition, you must right click on the frame and select “Hold In “. This selection will change the xaml to a “DiscreteDoubleKeyFrame ” from a “SplineDoubleKeyFrame “. Once you have created a key frame you must move the strip “canvas” to its desired position. Figure 2 shows what the completed animation sequence looks like in the designer.

framestoryboard.png



Figure 3 shows the xaml generated from this sequence.

sotryboardxaml.png



To check out my super simple animation done in Silverlight 1.1 click here.

Download: page.xaml
Download: Solution

Silverlight how-to: Animate a grid of tiles

An integral part of our proof-of-concept for the Phizzpop design challenge was a grid of tiles that represented a variety of TV shows and Movies. Transitioning from screen to screen we needed to repopulate this grid with a new set of tiles based on search criteria and filters. To improve the effect of repopulating the grid, we wanted to animate each tile as it was moved into its final position. Nothing crazy was desired, just a simple movement from the left, easing into its final position.

To achieve this effect, our initial approach was to hardcode a string of storyboard XAML. This animation was then inserted as a canvas resource and played to animate the tile movement. Programmatically, we would insert into a string of XAML the appropriate X and Y coordinates for each tiles final destination. Here is an example of what our original approach looked like.

1
2
3
4
5
6
7
8
9
10
11
12
13
xaml += "<Storyboard xmlns=\http://schemas.microsoft.com/client/2007\"
    xaml +=" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" x:Name=\""
    xaml += storyboardName + "\" Storyboard.TargetName=\"" + element.Name + "\" > "
  xaml += "  <DoubleAnimation Storyboard.TargetProperty=\"(Canvas.Left)\" To=\"" 
  xaml += currentX + "\" Duration=\"0:0:0.25\" />"
  xaml += " <DoubleAnimation Storyboard.TargetProperty=\"(Canvas.Top)\"  To=\""
  xaml +=  currentY + "\" Duration=\"0:0:0.25\" />"
xaml += "</Storyboard>"
 
  Storyboard storyboard = (Storyboard)XamlReader.Load(xaml)
 _parentCanvas.Resources.Add(storyboard)
 storyboard.Begin()
….

Even though this approach met our visual need, we felt it was a poor use of XAML and made tweaking the animation of each tile very difficult. Thanks to some great suggestions from a mentor at Microsoft, we came up with a much more flexible approach.

Instead of programmatically loading custom storyboard XAML into the resource collection, we created a single storyboard and added it as a canvas resource within the “tile.xaml“. This approach allowed us to use Blend to visualize the animation and manipulate its parameters until we got the desired easing and visual effect.

If you examine “tile.xaml there are a few things worth explaining. First, each “SplineDoubleKeyFrame” element has been given a “x:Name”. This name will be used to locate the appropriate “SplineDoubleKeyFrame” used to set the tiles destination X and Y “value”. Second, each “DoubleAnimationUsingKeyFrames” element is targeting the “parentCanvas”. In our tile class the top most canvas is named “parentCanvas”. This is significant, because it allows us to animate the entire tile element regardless of the number of visual elements nested within the UserControls XAML.

To facilitate the process of manipulating each “SplineDoubleKeyFrame” we have created the following helper function and placed it within our tile class.

1
2
3
4
5
6
7
8
9
public void SetSplineXandY(string sbName, string keyFrameXName, double x, string keyFrameYName, double y)
{
    Storyboard sb = _parentCanvas.Resources.FindName(sbName) as Storyboard
    SplineDoubleKeyFrame sdkY = sb.Children[0].FindName(keyFrameYName) as SplineDoubleKeyFrame
    sdkY.Value = y
 
    SplineDoubleKeyFrame sdkX = sb.Children[0].FindName(keyFrameXName) as SplineDoubleKeyFrame
    sdkX.Value = x
 }

As we populate the grid with tiles, we call “SetSplineXandY” to modify the appropriate X and Y coordinates prior ton playing the storyboard. Here is a snip of 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
foreach (Tile element in Children)
  {
  _Iteration++
  if (currentX + element.Width + marginX * 2 > panelWidth)
  {
   // move to next line
    currentX = 0 + marginX
    currentY = nextRowY + marginY
  }
  Storyboard sb = element.ParentCanvas.Resources.FindName("TileAnimation") as Storyboard
  //this is moving it immediatly to the correct Y
  element.SetValue(Canvas.TopProperty, currentY)
  element.SetValue(Canvas.LeftProperty, -150)
  sb.Completed += new EventHandler(TransitionIn_Completed)
  element.SetSplineXandY("TileAnimation", "keyFrameX", (currentX+150), "keyFrameY", 0.0)
  sb.Begin()
  _TransitionsInOut.Add(sb)
 
  // calculate offset for the next row
  nextRowY = Math.Max(nextRowY, currentY + element.Height + (marginY * 2))
 
  // calculate position for the next element
  currentX += element.Width + (marginX * 2)                  
}

Since we are executing a series of asynchronous storyboards it is beneficial to have a way to identify that all of the animations have completed. Individually, each storyboard fires a “Completed” event when it is finished. Attaching to this event combined with a collection of executed storyboards references we can determine when all storyboard are done playing.

That’s it. Click here to download a sample project that demonstrates this technique.

PhizzPop Design Challenge

phizzpop_logo.gifThe PhizzPop Design Challenge pits top interactive, Web, and design agencies against one another to push the limits of technology and creativity in a battle royale. Think Mad Max for design.

The regional teams have been selected and Terralever was selected.  To get prepared Scott, Craig and Myself will be attending two days of training in Los Angeles on Microsoft Expression Blend, WPF and Silverlight.  On December 3rd the Terralever team will be given a design problem and will have 3 days to come up with a solution.  On the fourth day we will return to Los Angeles and present our design to a panel of judges.  The winners will compete at the finals in Austin March 8th 2007 at this years SxSW conference.