I converted this lib from BlitzBasic:
name it :"npoly.bmx"
below is the demo
put both files in the same folder.
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