VB:Tutorials:Rectangular and Circular Collision Detection

From GPWiki
Jump to: navigation, search

Games aren't much fun without collisions.. I mean, really, would you play Mortal Kombat if there were no contact, no blood? It'd just be some sort of friendly martial-arts ballet!

Basic collision detection techniques should be sufficient for most games. Side scrollers, puzzle games, RPGs, and many others can get by with rectangular detection. Shooters and any sort of space game would likely be better off with circular detection. You'll see that these techniques are quite rudimentary.

Let me introduce you to my friend, the IntersectRect API call, and his buddy, the RECT type.

Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type
 
Declare Function IntersectRect Lib "user32" Alias "IntersectRect" _
    (lpDestRect As RECT, lpSrc1Rect As RECT, lpSrc2Rect As RECT) As Long

The IntersectRect function accepts three rectangles as arguments. It checks for intersection between the 2nd and 3rd arguments and places the resultant intersection rectangle in the first argument. Also, the function itself returns a value of 1 if there is an intersection, and a value of 0 if there is no intersection.

Obviously you could do these things manually with a number of If statements, but why bother? The IntersectRect API is simple to use, and fast. Watch:

mblnCollision = IntersectRect(udtTempRect, udtRect1, udtRect2)

This statement will check for intersection between udtRect1 and udtRect2 and assign the intersecting area to the rectangle udtTempRect. Also, if there IS an intersection, it will assign the value of True to the boolean mblnCollision. We can then take action based on the value of this boolean in other areas of the code.

Circular collision detection doesn't come with its own API call, so I've made my own function to speed things up a tad.

Private Function GetDist(intX1 As Single, intY1 As Single, intX2 As Single, intY2 As Single) As Single
    ' DaB - Don't use ^2 it's really slow.
    GetDist = Sqr((intX1 - intX2) * (intX1 - intX2) + (intY1 - intY2) * (intY1 - intY2))
 
End Function

This will return the distance between any two points in an X,Y plane. To find out how far away two circles are, pass the coordinates of their center points. Then subtract the radii of the two circles, and viola! You have the distance between the circles!

mblnCollision = (GetDist(msngCircle1X, msngCircle1Y, msngCircle2X, msngCircle2Y) <= RADIUS1 + RADIUS2)
 
'DaB - Or do it "inline in one line" if you need speed (and avoid the Sqr and ^2 operators)
mblnCollision = ((msngCircle1X-msngCircle2X)*(msngCircle1X-msngCircle2X)+(msngCircle1Y-msngCircle2Y)*(msngCircle1Y-msngCircle2Y)) <= (RADIUS1+RADIUS2)*(RADIUS1+RADIUS2)

Analogous to the rectangle code shown above, this code will assign True or False to the boolean depending on the outcome of the collision detection attempt. If the distance between the circles' centers is less than the sum of the radii, then they've collided. It's that easy.

Have a look at this sample source code which demonstrates these principles.