I converted this lib from BlitzBasic:
name it :"npoly.bmx"
' nPoly - Polygonal Collision Library
' By Jocelyn 'GoSsE' Perreault, <a href="http://www.nuloen.com/" target="_blank">http://www.nuloen.com/</a>
' Last Updated: July 8 2004
' Version: 1.0.0
' This source code is copyrighted (c) To Jocelyn Perreault.
' It is FreeWare. You have no limitiations in regard To
' applications/games that you Release/create with it, either
' they be freeware Or commercial. However, you cannot Release
' this source code under another name Or Release a similar
' library with it. It cannot be redistributed. The code may be
' modified To be tweaked but you cannot distribute it. If you
' made a modification that you think the community would
' benifit, please let me know.
' If you make tons of money with a commercial project,
' a free copy wouldn't hurt ')
' I would love To have an e-mail And a place in the credits
' of your projects, but it is up To you.
' Thanks,
' Jocelyn "GoSsE Korupted" Perreault
' gosse@...
' Nuclear Loaded Entertainment
' <a href="http://www.nuloen.com/" target="_blank">http://www.nuloen.com/</a>
' ======================================================================
' Globals And Constants
' ======================================================================
Const nP_MAX = 32 ' Maximum number of vertices For a poly
' ======================================================================
' Different objects
' ======================================================================
' Polygon
Type nP_Poly
Field iX[nP_MAX] ' Vertices X position
Field iY[nP_MAX] ' Vertices Y position
Field fX#[nP_MAX] ' Scaled And rotated X position
Field fY#[nP_MAX] ' Scaled And rotated Y position
Field iVertexCount ' Number of vertices
Field fScaleX# ' X-Scale
Field fScaleY# ' Y-Scale
Field fAngle# ' Angle rotation
Field iMinX ' Bounding box
Field iMinY ' Bounding box
Field iMaxX ' Bounding box
Field iMaxY ' Bounding box
End Type
' ======================================================================
' Functions
' ======================================================================
' Creates a New empty polygon
Function nP_CreatePoly:nP_Poly()
Local nPoly:nP_Poly = New nP_Poly
nPoly.fScaleX = 1
nPoly.fScaleY = 1
Return nPoly
End Function
' ----------------------------------------------------------------------
' Adds a vertex To a polygon
Function nP_AddVertex(poly:nP_Poly, x, y, bUpdate = True)
Local nPoly:nP_Poly = poly
If nPoly.iVertexCount > nP_MAX Then
RuntimeError "Cannot add one more vertex to polygon!"
Else
nPoly.iX[nPoly.iVertexCount] = x
nPoly.iY[nPoly.iVertexCount] = y
nPoly.iVertexCount = nPoly.iVertexCount + 1
If bUpdate Then
nP_UpdatePoly(poly)
End If
End If
End Function
' ----------------------------------------------------------------------
' Checks If 2 polygons overlap each other
Function nP_PolyOverlap(poly1:nP_Poly, x1, y1, poly2:nP_Poly, x2, y2, bCheckBounding = True)
' Polygons
Local nPoly1:nP_Poly = poly1
Local nPoly2:nP_Poly = poly2
' Temp positions
Local tx1#, ty1#, tx2#, ty2#, tx3#, ty3#, tx4#, ty4#
' Delta calculations
Local dSqr#, d1#, d2#, dx#, dy#
' Last vertex
Local lx1#, ly1#, lx2#, ly2#
' Counters
Local i, j
' Checks bounding box first (If specified)
If bCheckBounding Then
tx1 = X1 + nPoly1.iMinX
ty1 = Y1 + nPoly1.iMinY
tx2 = X1 + nPoly1.iMaxX
ty2 = Y1 + nPoly1.iMaxY
tx3 = X2 + nPoly2.iMinX
ty3 = Y2 + nPoly2.iMinY
tx4 = X2 + nPoly2.iMaxX
ty4 = Y2 + nPoly2.iMaxX
If Not (tx3 > tx1 And ty3 > ty1 And tx3 < tx2 And ty3 < ty2) Then
If Not (tx4 > tx1 And ty4 > ty1 And tx4 < tx2 And ty4 < ty2) Then
If Not (tx3 > tx1 And ty4 > ty1 And tx3 < tx2 And ty4 < ty2) Then
If Not (tx4 > tx1 And ty3 > ty1 And tx4 < tx2 And ty3 < ty2) Then
Return False
End If
End If
End If
End If
End If
' Store the last vertex
lx1 = nPoly1.fX#[0] + X1
ly1 = nPoly1.fY#[0] + Y1
lx2 = nPoly2.fX#[0] + X2
ly2 = nPoly2.fY#[0] + Y2
' Cycle through all other vertices
For i = 1 To nPoly1.iVertexCount - 1
For j = 1 To nPoly2.iVertexCount - 1
' Store vertices
tx1 = nPoly1.fX#[i] + X1
ty1 = nPoly1.fY#[i] + Y1
tx3 = nPoly2.fX#[j] + X2
ty3 = nPoly2.fY#[j] + Y2
tx2 = lX1
ty2 = lY1
tx4 = lX2
ty4 = lY2
' Calculate deltas
dSqr = (ty4-ty3)*(tx2-tx1)-(tx4-tx3)*(ty2-ty1)
d1 = (ty1-ty3)
d2 = (tx1-tx3)
dX = ((tx2-tx1)*d1-(ty2-ty1)*d2)
dY = ((tx4-tx3)*d1-(ty4-ty3)*d2)
' Parallel
If dSqr = 0 Then
' Coincident
If dX = 0 And dY = 0 Then
Return True
End If
Else
' Otherwise
d1 = dX / dSqr
d2 = dY / dSqr
If (d1 >= 0 And d1 <= 1) And (d2 >= 0 And d2 <= 1) Then
Return True
End If
End If
' Store last vertex
lX2 = tx3
lY2 = ty3
Next
' Store last vertex
lX1 = tx1
lY1 = ty1
Next
Return False
End Function
' ----------------------------------------------------------------------
Function nP_PolyOverlapsCircle(poly:nP_Poly, X, Y, iCircleX, iCircleY, iCircleRadius, bCheckBounding = True)
Local nPoly:nP_Poly = poly
' Temp positions
Local tx1#, ty1#, tx2#, ty2#, tx3#, ty3#, tx4#, ty4#
Local CX1#, CY1#, CX2#, CY2#, pX1#, pY1#, pX2#, pY2#, pXT#, pYT#
' Delta calculations
Local d1#, d2#, dX#, dY#, dSqr#
' Checks bounding box first (If specified)
If bCheckBounding Then
tx1 = X + nPoly.iMinX
ty1 = Y + nPoly.iMinY
tx2 = X + nPoly.iMaxX
ty2 = Y + nPoly.iMaxY
tx3 = iCircleX - iCircleRadius
ty3 = iCircleY - iCircleRadius
tx4 = iCircleX + iCircleRadius
ty4 = iCircleY + iCircleRadius
If Not (tx3 > tx1 And ty3 > ty1 And tx3 < tx2 And ty3 < ty2) Then
If Not (tx4 > tx1 And ty4 > ty1 And tx4 < tx2 And ty4 < ty2) Then
If Not (tx3 > tx1 And ty4 > ty1 And tx3 < tx2 And ty4 < ty2) Then
If Not (tx4 > tx1 And ty3 > ty1 And tx4 < tx2 And ty3 < ty2) Then
Return False
End If
End If
End If
End If
End If
' Store the last vertex & circle
lx = nPoly.fX#[0] + X
ly = nPoly.fY#[0] + Y
CX2# = iCircleX
CY2# = iCircleY
' Cycle through all other vertices
For i = 1 To nPoly.iVertexCount - 1
CX1# = nPoly.fX#[i] + X
CY1# = nPoly.fY#[i] + Y
pX1 = lX - CX1
pY1 = lY - CY1
pX2 = CX2 - CX1
pY2 = CY2 - CY1
d1 = pX1 * pX2 + pY1 * pY2
If d1 <= 0 Then
dX# = CX2 - CX1
dY# = CY2 - CY1
dSqr# = dX * dX + dY * dY
Else
d2 = pX1 * pX1 + pY1 * pY1
If (d2 <= d1) Then
dX# = CX2 - lX
dY# = CY2 - lY
dSqr# = dX * dX + dY * dY
Else
d1 = d1 / d2
pXT# = CX1 + d1 * pX1
pYT# = CY1 + d1 * pY1
dX# = CX2 - pXT
dY# = CY2 - PYT
dSqr# = dX * dX + dY * dY
End If
End If
If dSqr# < iCircleRadius * iCircleRadius Then
Return True
End If
lx = CX1
ly = CY1
Next
Return False
End Function
' ----------------------------------------------------------------------
' Returns True If both circles overlap
Function nP_CirclesOverlap(x1, y1, rad1, x2, y2, rad2)
Local dx# = x2 - x1
Local dy# = y2 - y1
Local rsqr = rad1 + rad2
rsqr = rsqr*rsqr
Return (dx*dx+dy*dy < rsqr)
End Function
' ----------------------------------------------------------------------
' Scales the polygon by the specified scale
Function nP_ScalePoly(poly:nP_Poly, sx#, sy#, bUpdate = True)
Local nPoly:nP_Poly = poly
nPoly.fScaleX# = nPoly.fScaleX# * sx#
nPoly.fScaleY# = nPoly.fScaleY# * sy#
If bUpdate Then
nP_UpdatePoly(poly)
End If
End Function
' ----------------------------------------------------------------------
' Resizes the polygon To the specieid scale
Function nP_ResizePoly(poly:nP_Poly, sx#, sy#, bUpdate = True)
Local nPoly:nP_Poly = poly
nPoly.fScaleX# = sx#
nPoly.fScaleY# = sy#
If bUpdate Then
nP_UpdatePoly(poly)
End If
End Function
' ----------------------------------------------------------------------
' Rotates the polygon by the specified rotation angle
Function nP_RotatePoly(poly:nP_Poly, fRot#, bUpdate = True)
Local nPoly:nP_Poly = poly
nPoly.fAngle# = nPoly.fAngle# + fRot#
If bUpdate Then
nP_UpdatePoly(poly)
End If
End Function
' ----------------------------------------------------------------------
' Turns the polygon To the specified angle
Function nP_FreeRotatePoly(poly:nP_Poly, fAngle#, bUpdate = True)
Local nPoly:nP_Poly = poly
nPoly.fAngle# = fAngle#
If bUpdate Then
nP_UpdatePoly(poly)
End If
End Function
' ----------------------------------------------------------------------
' Updates the polygon according To scale And rotation
Function nP_UpdatePoly(poly:nP_poly)
Local nPoly:nP_Poly = poly
Local fX#, fY#, f1#, f2#
Local i
' Set up big extremums
nPoly.iMinX = 9999999
nPoly.iMinY = 9999999
nPoly.iMaxX = -9999999
nPoly.iMaxY = -9999999
' Find a valid collision setting
For i = 0 To nPoly.iVertexCount - 1
' Standard data
fX = nPoly.iX[i]
fY = nPoly.iY[i]
' Scale
fX = fX * nPoly.fScaleX
fY = fY * nPoly.fScaleY
' Rotation
If nPoly.fAngle# <> 0 Then
f1 = Cos(nPoly.fAngle#) * fX - Sin(nPoly.fAngle#) * fY
f2 = Sin(nPoly.fAngle#) * fX + Cos(nPoly.fAngle#) * fY
fX = f1
fY = f2
End If
' Final Values
nPoly.fX#[i] = fX
nPoly.fY#[i] = fY
' Check For bounding box
If fX < nPoly.iMinX Then
nPoly.iMinX = fX
End If
If fY < nPoly.iMinY Then
nPoly.iMinY = fY
End If
If fX > nPoly.iMaxX Then
nPoly.iMaxX = fX
End If
If fY > nPoly.iMaxY Then
nPoly.iMaxY = fY
End If
Next
End Function
' ----------------------------------------------------------------------
' Draws the polygon on screen at the specified location
Function nP_DrawPoly(poly:nP_Poly, x, y, r=255, g=255, b=255, bDrawBoundingBox=True, br=255, bg=255, bb=255)
Local nPoly:nP_Poly = poly
Local i, lx, ly
' Draw bounding box (If specified)
If bDrawBoundingBox Then
SetColor br, bg, bb
DrawRect nPoly.iMinX + x, nPoly.iMinY + y, nPoly.iMaxX - nPoly.iMinX + 1, nPoly.iMaxY - nPoly.iMinY + 1', False
End If
' Draw all the lines
SetColor r, g, b
lx = nPoly.fX[0] + x
ly = nPoly.fY[0] + y
For i = 1 To nPoly.iVertexCount - 1
DrawLine lx, ly, nPoly.fX[i] + x, nPoly.fY[i] + y
lx = nPoly.fX[i] + x
ly = nPoly.fY[i] + y
Next
End Function
' ----------------------------------------------------------------------
' Copies a polygon And Return the newly created poly
Function nP_CopyPoly:nP_Poly(poly:nP_Poly)
Local nPoly:nP_Poly = poly
Local newPoly:nP_Poly = New nP_Poly
Local i
' Copy point data
For i = 0 To nPoly.iVertexCount - 1
newPoly.iX[i] = nPoly.iX[i]
newPoly.iY[i] = nPoly.iY[i]
newPoly.fX#[i] = nPoly.fX#[i]
newPoly.fY#[i] = nPoly.fY#[i]
Next
' Copy all data
newPoly.iVertexCount = nPoly.iVertexCount
newPoly.fScaleX# = nPoly.fScaleX#
newPoly.fScaleY# = nPoly.fScaleY#
newPoly.fAngle# = nPoly.fAngle#
newPoly.iMinX = nPoly.iMinX
newPoly.iMinY = nPoly.iMinY
newPoly.iMaxX = nPoly.iMaxX
newPoly.iMaxY = nPoly.iMaxY
Return newPoly
End Function
' ----------------------------------------------------------------------
' Deletes the polygon from memory
'Function nP_FreePoly(poly)
' Local nPoly.nP_Poly = Object.nP_Poly(poly)
' Delete nPoly
'End Function
below is the demo
put both files in the same folder.
SetGraphicsDriver GLMax2DDriver()
Graphics 640, 480, 0, 2
glEnable GL_LINE_SMOOTH
SeedRnd MilliSecs()
Global tmrFPS = CreateTimer(60)
AppTitle ="nPoly Demo"
Include "nPoly.bmx"
gear1 = nP_CreatePoly()
nP_AddVertex(gear1, 0, -50, False)
nP_AddVertex(gear1, 10, -10, False)
nP_AddVertex(gear1, 50, 0, False)
nP_AddVertex(gear1, 10, 10, False)
nP_AddVertex(gear1, 0, 50, False)
nP_AddVertex(gear1, -10, 10, False)
nP_AddVertex(gear1, -50, 0, False)
nP_AddVertex(gear1, -10, -10, False)
nP_AddVertex(gear1, 0, -50)
gear2 = nP_CopyPoly(gear1)
nP_ScalePoly(gear2, 0.7, 0.7)
lever = nP_CreatePoly()
nP_AddVertex(lever, -100, 5, False)
nP_AddVertex(lever, 0, 5, False)
nP_AddVertex(lever, 0, -5, False)
nP_AddVertex(lever, -100, -5, False)
nP_AddVertex(lever, -100, 5)
Const MAXC = 4
Local cylinder:nP_Poly[MAXC]
Local cy:Int[MAXC]
cylinder[0] = nP_CreatePoly()
nP_AddVertex(cylinder(0), -9, 20, False)
nP_AddVertex(cylinder(0), 9, 20, False)
nP_AddVertex(cylinder(0), 9, -20, False)
nP_AddVertex(cylinder(0), -9, -20, False)
nP_AddVertex(cylinder(0), -9, 20)
cy(0) = 100
For i = 0 To MAXC-1
cylinder(i) = nP_CopyPoly(cylinder[0])
cy(i) = cy(0)
Next
box = nP_CreatePoly()
nP_AddVertex(box, 0, 0, False)
nP_AddVertex(box, 200, 0, False)
nP_AddVertex(box, 170, 70, False)
nP_AddVertex(box, 200, 200, False)
nP_AddVertex(box, 30, 200, False)
nP_AddVertex(box, 65, 130, False)
nP_AddVertex(box, 0, 180, False)
nP_AddVertex(box, 0, 0)
rad = 15
maxb = 100
maxr = 15
minx = 20
miny = 270
maxx = 620
maxy = 460
Local balllist:TList
Type ball
Field poly
Field rad
Field x#
Field y#
Field velx#
Field vely#
End Type
For i = 1 To maxb
balls:ball = New ball
balls.x = Rnd(minx + maxr, maxx - maxr)
balls.y = Rnd(miny + maxr, maxy - maxr)
balls.rad = Rnd(4, maxr)
If Not balllist Then balllist = CreateList()
balllist.addlast(balls)
k = False
For b:ball = EachIn balllist
If b <> balls Then
If nP_CirclesOverlap(balls.x, balls.y, balls.rad, b.x, b.y, b.rad) Then
ListRemove(balllist,balls)
k = True
Exit
End If
End If
Next
If Not k Then
balls.velx = Rnd(0, 3) - 1.5
balls.vely = Rnd(0, 3) - 1.5
If Rand(1, 3) > 1 And balls.rad > 4 Then
balls.poly = nP_CreatePoly()
brad# = balls.rad
srad# = Rand(2, balls.rad - 2)
pikes = Rand(3, 7)
deg = 0
degstep = 180 / pikes
For j = 1 To pikes
nP_AddVertex(balls.poly, brad*Cos(deg), brad*Sin(deg), False)
deg = deg + degstep
nP_AddVertex(balls.poly, srad*Cos(deg), srad*Sin(deg), False)
deg = deg + degstep
Next
nP_AddVertex(balls.poly, brad*Cos(deg), brad*Sin(deg), False)
End If
End If
Next
While Not KeyDown(KEY_escape)
starttmr = MilliSecs()
WaitTimer tmrFPS
endtmr = MilliSecs()
timFPS = timFPS + endtmr - starttmr
If MilliSecs() > timFPS Then
timFPS = MilliSecs() + 1000
lastFPS = FPS
FPS = 0
Else
FPS = FPS + 1
End If
framestart = MilliSecs()
colchecks = 0
colchecks2 = 0
colchecks3 = 0
Cls
nP_RotatePoly(gear1, 1)
colchecks = colchecks + 1
' Gears
While nP_PolyOverlap(gear1, 150, 150, gear2, 212, 150, False)
nP_RotatePoly(gear2, -1)
colchecks = colchecks + 1
Wend
colchecks = colchecks + 1
' Gear And lever
If Not nP_PolyOverlap(gear2, 212, 150, lever, 320, 130, False)
nP_RotatePoly(lever, -1)
End If
colchecks = colchecks + 1
While nP_PolyOverlap(gear2, 212, 150, lever, 320, 130, False)
nP_RotatePoly(lever, 1)
colchecks = colchecks + 1
Wend
' Cylinders with lever
For i = 0 To MAXC-1
colchecks = colchecks + 1
If Not nP_PolyOverlap(cylinder(i), 230 + 22 * i, cy(i), lever, 320, 130, False)
cy(i) = cy(i) + 3
End If
colchecks = colchecks + 1
While nP_PolyOverlap(cylinder(i), 230 + 22 * i, cy(i), lever, 320, 130, False)
cy(i) = cy(i) - 1
colchecks = colchecks + 1
Wend
Next
' Resize box And mouse ball
If KeyDown(200) Then
nP_ScalePoly(box, 1.01, 1.01)
End If
If KeyDown(208) Then
nP_ScalePoly(box, 0.99, 0.99)
End If
If KeyDown(203) Then
nP_RotatePoly(box, 3)
End If
If KeyDown(205) Then
nP_RotatePoly(box, -3)
End If
rad = 15 + MouseZ() * 3
mx = MouseX()
my = MouseY()
nP_DrawPoly(gear1, 150, 150, 255, 0, 0, False)
nP_DrawPoly(gear2, 212, 150, 255, 0, 0, False)
nP_DrawPoly(lever, 320, 130, 255, 0, 0, False)
For i = 0 To MAXC-1
nP_DrawPoly(cylinder(i), 230 + 22 * i, cy(i), 255, 0, 0, False)
Next
DrawText "All polygonal collisions",110, 200
DrawText "done real-time",110,215
nP_DrawPoly(box, 400, 50, 255, 255, 0, False)
DrawText "Hover mouse about this box",400,5
DrawText "Arrow keys, mouse wheel",400,20
colchecks2 = colchecks2 + 1
If nP_PolyOverlapsCircle(box, 400, 50, mx, my, rad, False)
SetColor 0, 0, 255
Else
SetColor 255, 255, 255
End If
DrawOval mx - rad, my - rad, rad*2, rad*2
SetColor 0, 255, 0
'DrawRect minx, miny, maxx - minx, maxy - miny', False
For balls:ball = EachIn balllist
balls.x = balls.x + balls.velx
balls.y = balls.y + balls.vely
If balls.x + balls.rad >= maxx Or balls.x - balls.rad <= minx Then
balls.velx = -balls.velx
End If
If balls.y + balls.rad >= maxy Or balls.y - balls.rad <= miny Then
balls.vely = -balls.vely
End If
If balls.poly = 0 Then
DrawOval balls.x - balls.rad, balls.y - balls.rad, balls.rad*2, balls.rad*2
Else
nP_RotatePoly(balls.poly, balls.velx - balls.vely)
nP_DrawPoly(balls.poly, balls.x, balls.y, 0, 255, 0, False)
End If
For b:ball = EachIn balllist
If b <> balls Then
If b.poly = 0 And balls.poly = 0 Then
colchecks3 = colchecks3 + 1
col = nP_CirclesOverlap(balls.x, balls.y, balls.rad, b.x, b.y, b.rad)
ElseIf b.poly = 0 Then
colchecks2 = colchecks2 + 1
col = nP_PolyOverlapsCircle(balls.poly, balls.x, balls.y, b.x, b.y, b.rad)
ElseIf balls.poly = 0 Then
colchecks2 = colchecks2 + 1
col = nP_PolyOverlapsCircle(b.poly, b.x, b.y, balls.x, balls.y, balls.rad)
Else
colchecks = colchecks + 1
col = nP_PolyOverlap(balls.poly, balls.x, balls.y, b.poly, b.x, b.y)
End If
If col Then
x# = balls.x - b.x
y# = balls.y - b.y
balls.velx = Abs(balls.velx) * Sgn(x#)
balls.vely = Abs(balls.vely) * Sgn(y#)
b.velx = Abs(b.velx) * -Sgn(x#)
b.vely = Abs(b.vely) * -Sgn(y#)
tx# = balls.velx * 0.7 + Abs(b.velx) * Sgn(x#) * 0.3
ty# = balls.vely * 0.7 + Abs(b.vely) * Sgn(y#) * 0.3
b.velx = b.velx * 0.7 + Abs(balls.velx) * -Sgn(x#) * 0.3
b.vely = b.vely * 0.7 + Abs(balls.vely) * -Sgn(y#) * 0.3
balls.velx = tx#
balls.vely = ty#
Exit
End If
End If
Next
Next
SetColor 255, 255, 255
DrawText "FPS: " + lastfps,0,0
DrawText "Collision checks:",0,15
DrawText "Poly vs poly: " + colchecks,0,30
DrawText "Poly vs circle: " + colchecks2,0,45
DrawText "Circle vs circle: " + colchecks3,0,60
DrawText "Total: " + (colchecks + colchecks2 + colchecks3),0,75
Flip False
Wend
End