Collision Detection XNA 4.0

lxXTaCoXxl 0 Tallied Votes 245 Views Share

I had a small problem with collision detection starting out with XNA 4.0 so I figured I'd release a simple snippet that helps with two different types of collision detection; Per-Pixel and Rectangular.

To use simply copy and paste the snippet into your current source, or you could put it into an application extension so you don't have to find the source code over and over again.

I'm developing a beginners developer kit for XNA 4.0 for those who are interested in XNA development but don't know quite where to start. There are several game helpers as well as some useful methods for XNA Development. The most useful being some physics methods; motion (movement on x and y), jumping (simulation of fake gravity), drag, heat, and much more; as well as some useful methods for AI; for example, Bezier curves, pathfinding, decision simulation, button combos, so on and so forth. So you can look forward to that if you're interested in learning XNA. I will include the kit with a simple showroom style app/game that will print source code, show debugging values, and what all is going on in each area. It includes 9 basic games to play around with, and learn how to make. It will be freeware so that's a plus as well. :)

Hope it helps,
Jamie - Studio 41 Games (Owner / Head Developer)

public class CollisionDetection {
        public static bool PerPixel(Rectangle RectangleA, Texture2D SpriteA, Rectangle RectangleB, Texture2D SpriteB) {
            Color[] DataA = new Color[SpriteA.Width * SpriteA.Height];
            SpriteA.GetData(DataA);

            Color[] DataB = new Color[SpriteB.Width * SpriteB.Height];
            SpriteB.GetData(DataB);

            int Top = System.Math.Max(RectangleA.Top, RectangleB.Top);
            int Bottom = System.Math.Min(RectangleA.Bottom, RectangleB.Bottom);
            int Left = System.Math.Max(RectangleA.Left, RectangleB.Left);
            int Right = System.Math.Min(RectangleA.Right, RectangleB.Right);

            for (int y = Top; y < Bottom; y++) {
                for (int x = Left; x < Right; x++) {
                    Color ColorA = DataA[(x - RectangleA.Left) + (y - RectangleA.Top) * RectangleA.Width];
                    Color ColorB = DataB[(x - RectangleB.Left) + (y - RectangleB.Top) * RectangleB.Width];

                    if (ColorA.A > 30 && ColorB.A > 30) {
                        return true;
                    }
                }
            }

            return false;
        }

        public static bool Rectangular(Rectangle RectangleA, Rectangle RectangleB) {
            return RectangleA.Intersects(RectangleB);
        }
skatamatic 371 Practically a Posting Shark

Wouldn't checking for collisions per pixel be extremely expensive cpu wise?

lxXTaCoXxl 26 Posting Whiz in Training

In a way yes, but at the same time per-pixel is a lot better than rectangular. Rectangular collision detection just checks the location of the object plus it's width and height to see if it intersects with another object. Where per-pixel goes through each pixel in the sprite to see if the alpha channel of the sprite is greater than 30 and if it intersects with a second sprite in an area that has an alpha channel of greater than 30. Thus creating an actual collision, because not all sprites fit their rectangles perfectly. There are plenty of other ways to detect for collision but these two are the most commonly used and the easiest to implement.

skatamatic 371 Practically a Posting Shark

Makes sense :). But when scaled to 3 dimensions pixel by pixel is pretty well out of the question as the number of pixels to check grows exponentially. But for 2D collisions perhaps doing the rectangular check as a filter to determine a potential collision, then doing the pixel by pixel on these 2 sprites would be a nice and efficient mix of the two.

How might these collision detections be used to determine the hit heading (where with relation to center of gravities did the objects collide). I believe this is essential for determining things like the resulting momentum and angular velocity of the two objects.

lxXTaCoXxl 26 Posting Whiz in Training

You could create a Vector style variable to hold the point of impact and then store the impact values when detecting the collision of alpha channels:

public static Vector2 PointOfImpact;

if (ColorA.A > 30 && ColorB.A > 30) {
    PointOfImpact = new Vector2(SpriteA.X + x, SpriteA.Y + y);
    return true;
}

It's not pretty or completely accurate but gives you a basic idea of how to calculate the point of impact for determining other "physical" variables. That was a great question; and I did not expect that in any way. LOL

lxXTaCoXxl 26 Posting Whiz in Training

Also resulting momentum of collision would be determined by the momentum of both objects (I believe it's multiplication, can't remember). You could do some pretty interesting stuff to bi-dimensional sprites using a point of impact in relation to center of gravity of both sprites. You could create some interesting spin, movement, destruction, and other cool things. The list would go on and on, depending on what your imagination can give you to use. :)

skatamatic 371 Practically a Posting Shark

Thats true for basic objects. But say you had a long skinny rectangle that is hit on a far edge by something with a lot of momentum. Assuming a fairly low weight on the rectangle and high weight on the colliding object, it should simply spin in place and slightly affect the speed/angle of the colliding object. Since it was collided very far from the center of gravity (the exact middle of the rectangle) the momentum should be applied to angular velocity (how fast its spinning) and have no effect on the actual position of the rectangle. That is not to say, however, that the rectangle has no momentum. If a ball is dropped in its path while spinning it should still transfer its rotational momentum to the object (ie launch it into space).

I'm no physics expert but these kinds of problems are very interesting to me :)

tpb_rocpile 0 Newbie Poster

Hi Jamie. This developers kit sounds very interesting. Hope to see another post soon!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.