Accessibility help

Developers guide to writing a simple Silverlight game

Collision detection

Ah my old friend (and enemy), collision detection. This is where you realise Silverlight isn't a game framework because there is no out-of-the-box hit test. Ok not to worry, what we do have is the rather strange concept of the canvas. Like a container, a canvas is used to group a set of controls and help position them. But unlike a container the controls are not constrained by their canvas, you can draw off the canvas...weird. So really the name canvas is a misnomer, it's really a grouping & relative positioning container...Ok maybe canvas will do ;) But what this means is that the canvas can provide a nice, if primative, form of collision detection. Using the canvas and the detectors bounding box means we can not only provide a very efficient hit test but we can also easily exclude graphical assets (such as smoke or spray) from creating a collision. Just in case you're not familiar with such tests this is the one I used;

public static bool Collision(Sprite sprite1, Sprite sprite2)

{

   double left1 = (double)sprite1.GetValue(Canvas.LeftProperty);

   double left2 = (double)sprite2.GetValue(Canvas.LeftProperty);

   double top1 = (double)sprite1.GetValue(Canvas.TopProperty);

   double top2 = (double)sprite2.GetValue(Canvas.TopProperty);

   double actualWidth = sprite1.ActualWidth;

   double actualHeight = sprite1.ActualHeight;

   GetActualSizesForTransformedSprite(sprite1, ref actualWidth, ref actualHeight);

   //See if the sprite rectangles overlap

   bool collision = !(left1 > left2 + sprite2.ActualWidth

   || left1 + actualWidth < left2

   || top1 > top2 + sprite2.ActualHeight

   || top1 + actualHeight < top2);

   return collision;

}

The observant amongst you may have noticed GetActualSizesForTransformedSprite, this represented my biggest problem. One of our characters is a big jet plane that acts as a end of level boss. Although it moves around the screen using the same techniques as any other character the plane also zooms in and out using a transform. This caused a big problem with the collision detection. When I asked for it's actual size Silverlight would always tell me the size of the sprite in it's normal form, regardless of if it was currently fully zoomed in (or out). I have to thank dcstraw from the Silverlight.net forums for the core of the solution;

//game controller

private static void GetActualSizesForTransformedSprite(Sprite sprite1, ref double actualWidth,

   ref double actualHeight)

{

   PlaneControl plane = sprite1 as PlaneControl;

   if (plane != null)

   {

     Rect bounds = plane.GetRenderBounds(Application.Current.RootVisual);

     actualWidth = bounds.Width;

     actualHeight = bounds.Height;

   }

}

?

// Plane control

public Rect GetRenderBounds(UIElement relativeTo)

{

   var transform = LayoutRoot.TransformToVisual(relativeTo);

   var topLeft = transform.Transform(new Point(0, 0));

   var topRight = transform.Transform(new Point(ActualWidth, 0));

   var bottomRight = transform.Transform(new Point(ActualWidth, ActualHeight));

   var bottomLeft = transform.Transform(new Point(0, ActualHeight));

   double boundsLeft = Math.Min(topLeft.X, Math.Min(topRight.X,

      Math.Min(bottomRight.X, bottomLeft.X)));

   double boundsTop = Math.Min(topLeft.Y, Math.Min(topRight.Y,

     Math.Min(bottomRight.Y, bottomLeft.Y)));

   double boundsRight = Math.Max(topLeft.X, Math.Max(topRight.X,

     Math.Max(bottomRight.X, bottomLeft.X)));

   double boundsBottom = Math.Max(topLeft.Y, Math.Max(topRight.Y,

     Math.Max(bottomRight.Y, bottomLeft.Y)));

return new Rect(boundsLeft, boundsTop, boundsRight - boundsLeft,

   boundsBottom - boundsTop);

}

Miscellaneous issues & tips >>

<< Animations

collision detection on spray can collision detection on spray can