Silverlight Feeds - All your Silverlight feeds in one place.

Sponsors

Friday, July 10, 2009

Improved HitTest Method for Silverlight 3

by andy@andybeaulieu.com via Andy's Blog on 7/10/2009 1:24:00 PM


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.

 

 

email it!bookmark it!digg it!

Original Post: Improved HitTest Method for Silverlight 3

Subscribe

New Feed

Product Spotlight

Recently Updated Sources

Legal Note

The content of the postings is owned by the respective author. Silverlight Feeds is not responsible for the contents of the postings. This site is automatically generated and cannot be reviewed for abusive content. If you find abusive content on Silverlight Feeds, please contact us. Designated trademarks and brands are the property of their respective owners. All rights reserved.

Advertise with us