# Difference between revisions of "VB:Tutorials:Rectangular and Circular Collision Detection"

m (Marked for broken markup) |
(s/code/syntaxhighlight/ for all code fragments) |
||

Line 1: | Line 1: | ||

− | |||

− | |||

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! | 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! | ||

Line 7: | Line 5: | ||

Let me introduce you to my friend, the <tt>IntersectRect</tt> API call, and his buddy, the <tt>RECT</tt> type. | Let me introduce you to my friend, the <tt>IntersectRect</tt> API call, and his buddy, the <tt>RECT</tt> type. | ||

− | < | + | <syntaxhighlight type="vb"> |

Type RECT | Type RECT | ||

Left As Long | Left As Long | ||

Line 17: | Line 15: | ||

Declare Function IntersectRect Lib "user32" Alias "IntersectRect" _ | Declare Function IntersectRect Lib "user32" Alias "IntersectRect" _ | ||

(lpDestRect As RECT, lpSrc1Rect As RECT, lpSrc2Rect As RECT) As Long | (lpDestRect As RECT, lpSrc1Rect As RECT, lpSrc2Rect As RECT) As Long | ||

− | </ | + | </syntaxhighlight> |

The <tt>IntersectRect</tt> 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 <tt>1</tt> if there is an intersection, and a value of <tt>0</tt> if there is no intersection. | The <tt>IntersectRect</tt> 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 <tt>1</tt> if there is an intersection, and a value of <tt>0</tt> if there is no intersection. | ||

Line 23: | Line 21: | ||

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

− | < | + | <syntaxhighlight type="vb"> |

mblnCollision = IntersectRect(udtTempRect, udtRect1, udtRect2) | mblnCollision = IntersectRect(udtTempRect, udtRect1, udtRect2) | ||

− | </ | + | </syntaxhighlight> |

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

Line 31: | Line 29: | ||

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

− | < | + | <syntaxhighlight type="vb"> |

Private Function GetDist(intX1 As Single, intY1 As Single, intX2 As Single, intY2 As Single) As Single | 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. | ' DaB - Don't use ^2 it's really slow. | ||

Line 37: | Line 35: | ||

End Function | End Function | ||

− | </ | + | </syntaxhighlight> |

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! | 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! | ||

− | < | + | <syntaxhighlight type="vb"> |

mblnCollision = (GetDist(msngCircle1X, msngCircle1Y, msngCircle2X, msngCircle2Y) <= RADIUS1 + RADIUS2) | 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) | '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) | mblnCollision = ((msngCircle1X-msngCircle2X)*(msngCircle1X-msngCircle2X)+(msngCircle1Y-msngCircle2Y)*(msngCircle1Y-msngCircle2Y)) <= (RADIUS1+RADIUS2)*(RADIUS1+RADIUS2) | ||

− | </ | + | </syntaxhighlight> |

Analogous to the rectangle code shown above, this code will assign <tt>True</tt> or <tt>False</tt> 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. | Analogous to the rectangle code shown above, this code will assign <tt>True</tt> or <tt>False</tt> 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. |

## Latest revision as of 18:09, 3 July 2014

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.