Home > Client Technologies, Tutorials > BugCamSmash Dissected part 1 – Smash a Bug

BugCamSmash Dissected part 1 – Smash a Bug

December 4, 2009

When beginning the project that became BugCamSmash, I knew I was going to try and interact with the UI using the new webcam feature in some way. My first step then was to find a good method for hit detection as well as a good target to hit.

Now normally, I’m a peaceful being who tries to “free” insects and creatures that find themselves in my oh-so-humanly claimed living space. But sometimes when finding a creature that looks dangerous or as if it might sting or bite, caveman instincts kick in and I choose to smash.

Therefore bugs were a naturally choice as the target to “hit”.

Creating the Bug

bug in design view

I chose to create a .png for the body or shell of the beetle because I knew I was going for a somewhat realistic look and it is simpler to do subtle bevel-like features rasterized rather than vectors. I also knew I wouldn’t be animating the shell in any way.

The legs and antennae would be animated though, so those were drawn in Blend as Paths.  I drew one set of three legs first, grouped them into a Canvas and copied another and flipped it horizontally.  The antennae were then drawn in and I created a Twitch Storyboard to show them quickly moving inwards.  This was done by animating the individual points on each antenna Path over a very short period of time.

Then I added a simple Smash Storyboard rotating and repositioning the leg and antenna parts to be played after a hit detection is made.

Now to hook up the Storyboards in the class file, I created EventHandler for the Loaded event of the Bug, another handler for the time completed event, a Smash method and a Smashed property:

public bool Smashed { get; set; }

void Bug_Loaded(object sender, RoutedEventArgs e)
{
   r = new Random();
   timer = new Storyboard();
   timer.Duration = TimeSpan.FromMilliseconds(1000);
   timer.Completed += new EventHandler(timer_Completed);
   timer.Begin();
}

void timer_Completed(object sender, EventArgs e)
{
   Twitch.Begin();
   timer.Duration = TimeSpan.FromMilliseconds(r.Next(1000, 10000));
   timer.Begin();
}

public void Smash()
{
   Smashed = true;
   timer.Stop();
   SmashAnim1.Begin();
}

On load, the timer Storyboard is instantiated to randomly call the Twitch animation repeatedly. And Smash is a public method used to stop the random twitching and play the Smash animation to break the legs of the bug.

Placing the Bug on the Screen

Now that I have my bug, I wanted to randomly place it on the screen. This was accomplished by adding the following code to the MainPage:

void MainPage_Loaded(object sender, RoutedEventArgs e)
{
   r = new Random(); 
}

void MainPage_SizeChanged(object sender, SizeChangedEventArgs e)
{
   if (firstSizeChanged) 
      AddBug(); 
}

void AddBug()
{
   Bug b = new Bug(); 
   Canvas.SetLeft(b, r.NextDouble() * LayoutRoot.ActualWidth – bugWidth); 
   Canvas.SetTop(b, r.NextDouble() * LayoutRoot.ActualHeight – bugHeight); 
   LayoutRoot.Children.Add(b); 
}

bug randomly placed

On Load of MainPage, I create a new Random object.  Then, the first time MainPage changes size I run the AddBug method.  No specific Height and Width is set to LayoutRoot, the main Canvas, so that it will span the full size of the application host (determined by the size of the object tag in the html). This results in Width and Height always returning 0, and not being useful when attempting to randomly place the bug.

To learn the width and height of the LayoutRoot Canvas, we must wait until Silverlight’s layout system has completed the measure and arrange process which fires the SizeChanged event. At this point we can use the ActualWidth and ActualHeight properties to randomly position the bug within the bounds of LayoutRoot.

Then we add the bug as a child of LayoutRoot and we’re ready.  All we need is a rock to smash it.

Adding the Smashing Rock

The rock is simply a bunch of Paths grouped into a Canvas with two important features. First the rock’s ZIndex is set to 999, so when the bug is added dynamically it will be behind the rock. Second the interactivity of dragging the rock with a mouse and smashing the bug is handled with a custom behavior.

The behavior appropriately called BugSmashDrag is very similar to the default MouseDrag behavior with two added features: bug locating on mouse down and bug smashing on mousemove.

private void findBugs()
{
   Panel parent = AssociatedObject.Parent as Panel
   Bug b = null
   bugs.Clear(); 
   foreach (UIElement uie in parent.Children) 
   { 
      if (uie is Bug
      { 
         b = uie as Bug
         if (!b.Smashed) 
            bugs.Add(b); 
      } 
   } 
}

private void AssociatedObjectMouseMove(object sender, MouseEventArgs e)
{
   […mouse move code…]

   foreach (Bug b in bugs) 
   { 
      if (checkCollision(AssociatedObject, b)) 
      { 
         b.Smash(); 
         findBugs(); 
         break
      } 
   }
}

bug randomly placed

On MouseLeftButtonDown of the object that the behavior is attached to (in this case the rock), mouse dragging begins and an inventory is taken and stored of how many bugs there are in the parent Canvas LayoutRoot.

Then when the Mouse is moved the checkCollosion1 method is called comparing the bounds of the rock and the bug. When the bounds intersect, the Smash method is called on the instance of bug and we have success!

A smashed bug.

The next step will cover making the bugs “crawl” based on where the mouse is clicked

 

1 Using Andy Beaulieu’s posted Silverlight HitTest method

About these ads
  1. No comments yet.
Comments are closed.
Follow

Get every new post delivered to your Inbox.

Join 29 other followers

%d bloggers like this: