SpriteHand
Module Border
  Improved HitTest Method for Silverlight 3
Module Border
Location: BlogsAndy's Blog    
Posted by: host 7/10/2009 8:24 AM


With the new Silverlight 3 WriteableBitmap class, it’s possible to do pixel-perfect collision detection (a “HitTest”) on bitmap (raster) images. In a
previous blog post, I showed how we can do a HitTest on Vector graphics in Silverlight 2. In this blog post, we’ll enhance the collision detection to handle BOTH Vector graphics and Raster graphics in Silverlight 3.

VIEW THE DEMO        

DOWNLOAD THE SOURCE

Looking at the demo code, one of the main routines is the CheckCollisionPoint class, which does a HitTest on a UI Element at a specific Point. If the element is an Image, then a WriteableBitmap object is used to check the specific pixel point (this WriteableBitmap is created in the CheckCollision method, shown later.). If the element is not an image, then we assume it is Vector based and we use the VisualTreeHelper class for a hit test:

public bool CheckCollisionPoint(Point pt, FrameworkElement control, FrameworkElement controlElem)

{

    if (controlElem is Image)

    {

        // NOTE that we saved the WB in the Tag object for performance.

        // in a real app, you would abstract this in your sprite class.

        WriteableBitmap wb = controlElem.Tag as WriteableBitmap;

 

        int width = wb.PixelWidth;

        int height = wb.PixelHeight;

 

        double offSetX = Convert.ToDouble(control.GetValue(Canvas.LeftProperty));

        double offSetY = Convert.ToDouble(control.GetValue(Canvas.TopProperty));

 

        pt.X = pt.X - offSetX;

        pt.Y = pt.Y - offSetY;

 

        int offset = Convert.ToInt32((width * pt.Y) + pt.X);

 

return (wb.Pixels[offset] != 0);

    }

    else

    {

        List<UIElement> hits = System.Windows.Media.VisualTreeHelper.FindElementsInHostCoordinates(pt, controlElem) as List<UIElement>;

        return (hits.Contains(controlElem));

    }

}

The CheckCollisionPoint method is used by the CheckCollision method, which checks for a collision between two UI elements. Note that we always want to do a quick Rect.Intersect test on the bounds of the elements before doing the slower per-pixel Hit Test. This method also creates the WriteableBitmap and stores it in the Tag property (you may want to abstract this into a Sprite class in a real application):

private bool CheckCollision(FrameworkElement control1, FrameworkElement controlElem1, FrameworkElement control2, FrameworkElement controlElem2)

{

    // first see if sprite rectangles collide

    Rect rect1 = UserControlBounds(control1);

    Rect rect2 = UserControlBounds(control2);

 

    rect1.Intersect(rect2);

    if (rect1 == Rect.Empty)

    {

        // no collision - GET OUT!

        return false;

    }

    else

    {

        bool bCollision = false;

        Point ptCheck = new Point();

 

        // NOTE that creating the writeablebitmap is a bit intense

        // so we will do this once and store results in Tag property

        // in a real game, you might abstract this into a Sprite class.

        if (controlElem1 is Image)

            controlElem1.Tag = GetWriteableBitmap(control1);

 

        if (controlElem2 is Image)

            controlElem2.Tag = GetWriteableBitmap(control2);

 

        // now we do a more accurate pixel hit test

        for (int x = Convert.ToInt32(rect1.X); x < Convert.ToInt32(rect1.X + rect1.Width); x++)

        {

            for (int y = Convert.ToInt32(rect1.Y); y < Convert.ToInt32(rect1.Y + rect1.Height); y++)

            {

                ptCheck.X = x;

                ptCheck.Y = y;

 

 

                if (CheckCollisionPoint(ptCheck, control1, controlElem1))

                    if (CheckCollisionPoint(ptCheck, control2, controlElem2))

                    {

                        bCollision = true;

                        break;

                    }

 

            }

            if (bCollision) break;

        }

        return bCollision;

    }

}

A quick note about performance: This method provides a simple way of getting pixel-perfect collision detection in Silverlight 3. But if you have a lot of elements that are colliding simultaneously (without being destroyed), this may not perform well.  Also, high velocity objects could pass through each other.

 

 

Permalink |  Trackback

Comments (10)   Add Comment
andy.beaulieu.com > Home - Improved HitTest Method for Silverlight 3    By TrackBack on 7/11/2009 8:00 AM
Thank you for submitting this cool story - Trackback from NewsPeeps
# NewsPeeps

Re: Improved HitTest Method for Silverlight 3    By Anonymous on 7/12/2009 1:44 PM
Good Work, that goes for You and the SL team.

Merry X-Mas Silverlight 3    By TrackBack on 12/24/2009 12:40 PM
Merry X-Mas Silverlight 3
# Wesly van Zoen

Re: Improved HitTest Method for Silverlight 3    By Anonymous on 1/23/2010 3:42 AM
Thanks a lot man .... amazing work you have here. Thanks for sharing.

Re: Improved HitTest Method for Silverlight 3    By Anonymous on 2/18/2010 5:01 AM
Your function UserControlBounds in the sample code doesn't work correctly if an object is in a grid and/or uses automatic widths and heights. Setting it to use ActualWidth and ActualHeight will fix part of the problem, but getting the topLeft coordinate is proving a bit trickier. I've tried using control.TransformToVisual(Application.Current.RootVisual).Transform(new Point()); but that throws an exception of "Value does not fall within the expected range." Any suggestions?

Merry X-Mas Silverlight 3    By TrackBack on 2/22/2010 11:28 AM
Merry X-Mas Silverlight 3
# www.wez.nl

Re: Improved HitTest Method for Silverlight 3    By Anonymous on 6/7/2010 12:20 PM
Hey Andy, I made a video tutorial on your HitTest technique: http://tinyurl.com/2bgbp7s

Thanks very much this is an awesome technique!

Victor Gaudioso

Re: Improved HitTest Method for Silverlight 3    By Anonymous on 7/28/2010 9:04 PM
Hello and thank for your post. I was wanting to use something like this, but I'm using keydown for my movement. How would I incorporate this so I couldn't move in a direction if there's a collision?

Thanks in advance
Logan

Re: Improved HitTest Method for Silverlight 3    By Anonymous on 2/28/2011 2:53 PM
Thanks very much. I created a game using your technique, is a simple arcade shooter.

Greetings!

Re: Improved HitTest Method for Silverlight 3    By Anonymous on 2/28/2011 2:56 PM
I'm sorry, I forgot to put the link of the game:) is this

http://www.mashooo.com/SilverlightGames/Rapid_Destroyer.aspx

Greetings!


Title:
Comment:
Add Comment   Cancel 
Module Border Module Border
Module Border
  Subscribe
Module Border
RSS   Twitter
Module Border Module Border
Module Border
  Diversions
Module Border

TALKING RAGDOLL
This Windows Phone 7 App was created using Silverlight, the  Physics Helper Library,  and the Farseer Physics Engine. It gets interesting when you import your friends photos and have your way with them!

MORE INFO



DROPPYPOP
This Windows Phone 7 game was created using Silverlight, the  Physics Helper Library,  and the Farseer Physics Engine.
DEMO

MORE INFO



BOSS LAUNCH
This physics game won first place in the Server Quest Contest. Created using Silverlight 2, the Physics Helper Library,  and the Farseer Physics Engine.
PLAY IT

MORE INFO



DESTROY ALL INVADERS
A scrolling shooter game where the objective is to destroy the invading UFO's flying over a neighborhood of your choosing. Imagery provided by Microsoft Virtual Earth. Created using Silverlight 2.
PLAY IT

INFO AND CODE



PHYSICS HELPER DEMOS
These demos were created for the Physics Helper Library, which makes it easy to create physics games and simulations using Expression Blend, Silverlight, and the Farseer Physics Engine.
PLAY IT

INFO AND CODE



HOOK SHOT
This little basketball game took first place in the TeamZoneSports Silverlight Contest. Created using Silverlight 2 and the Farseer Physics engine.
PLAY IT

MORE INFO



SORT THE FOOBARS
A game where you need to sort the good foobars from the bad ones. Created using Silverlight 2 and the Farseer Physics engine.
PLAY IT

MORE INFO



POLYGON PHYSICS DEMO
A demo showing polygon physics where the user draws physics objects with the mouse. Created using Silverlight 2 and the Farseer Physics engine.
PLAY IT

MORE INFO



SILVERLIGHT ROCKS!
Destroy the asteroids before they destroy your ship! Created using Silverlight 2.
PLAY IT

INFO AND CODE



FISH GAME
A simple game of harpoon-the-fish. Written using the AJAX Sprite Toolkit.
PLAY IT

INFO AND CODE

Module Border Module Border
Module Border
  Search_Blog
Module Border
Module Border Module Border
Module Border
  Blog_Archive
Module Border
Module Border Module Border
Copyright (c) 2014 andy.beaulieu.com - Login