Code archives/Algorithms/2D Collision Example
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
Create circles and lines that collide with each other. | |||||
;2D Collision Example By Jeppe Nielsen 2004 ;nielsen_jeppe@hotmail.com ; ;Added June 28th 2004: ;global variables to get the intersection or collision point between a line and a circle. ;use these globals to get the collision point between a circle and a line. Global LineCollisionX# Global LineCollisionY# Graphics 800,600,16,2 SetBuffer BackBuffer() ;Create lines at screen edges LineNew(0,0,800,0) LineNew(800,0,800,600) LineNew(0,600,800,600) LineNew(0,0,0,600) ;Create two Circles CircleNew(100,100,20,0.4,0.2) CircleNew(200,100,50,-0.2,0.3) event=0 cline.cline=Null Repeat Cls If MouseHit(2) CircleNew(Rnd(200,600),Rnd(100,500),Rnd(10,40),Rnd(-2,2),Rnd(-2,2)) EndIf Select event Case 0 If MouseHit(1) x1#=MouseX() y1#=MouseY() event=1 cline=LineNew(x1#,y1#,x1+10,y1) EndIf Case 1 LineRecalc(cline,x1,y1,MouseX(),MouseY()) If MouseHit(1) event=0 EndIf End Select ;Update and draw stuff CircleUpdate() PoofUpdate() CircleDraw() LineDraw() PoofDraw() Text 400,10,"2D Collision Example by Jeppe Nielsen 2004",1,0 Text 400,30,"Left mouse button to create lines",1,0 Text 400,50,"Right mouse button to create more circles",1,0 Flip Until KeyDown(1) End Type cline Field x1#,y1#,x2#,y2#,nx#,ny#,ux#,uy# End Type Function LineNew.cline(x1#,y1#,x2#,y2#) l.cline=New cline LineRecalc(l,x1#,y1#,x2#,y2#) Return l End Function Function LineRecalc(l.cline,x1#,y1#,x2#,y2#) l\x1=x1 l\y1=y1 l\x2=x2 l\y2=y2 dx#=l\x2-l\x1 dy#=l\y2-l\y1 d#=Sqr(dx*dx+dy*dy) If d#<0.0001 d#=0.0001 EndIf l\ux=dx/d l\uy=dy/d l\nx#=l\uy l\ny#=-l\ux End Function Function LineDraw() For l.cline=Each cline Color 255,255,255 Line l\x1,l\y1,l\x2,l\y2 Color 255,255,0 ;Draw normal xm#=(l\x1+l\x2)/2.0 ym#=(l\y1+l\y2)/2.0 Line xm,ym,xm+l\nx*10,ym+l\ny*10 Next End Function ;Global LineCollisionX# ;Global LineCollisionY# ;Returns the shortest distance from a point to a line ;Use LineCollisionX and LineCollisionY to get the collision point. Function LineDistance#(l.cline,x#,y#) dx#=l\x2-l\x1 dy#=l\y2-l\y1 d#=Sqr(dx*dx+dy*dy) px#=l\x1-x# py#=l\y1-y# dist#=(dx*py-px*dy) / d LineCollisionX=x#-l\nx*dist# LineCollisionY=y#-l\ny*dist# Return Abs(dist#) End Function ;Returns true if a point collides with a line within range r Function LineCollide(l.cline,x#,y#,r#) dx1#=x-(l\x1-l\ux*r) dy1#=y-(l\y1-l\uy*r) d#=Sqr(dx1*dx1+dy1*dy1) dx1=dx1/d dy1=dy1/d dx2#=x-(l\x2+l\ux*r) dy2#=y-(l\y2+l\uy*r) d#=Sqr(dx2*dx2+dy2*dy2) dx2=dx2/d dy2=dy2/d dot1#=dx1*l\ux+dy1*l\uy dot2#=dx2*l\ux+dy2*l\uy Return ((dot1#>=0 And dot2#<=0) Or (dot1#<=0 And dot2#>=0)) And (LineDistance(l,x,y)<=r) End Function Type circle Field x#,y#,vx#,vy# Field vel# Field r# End Type Function CircleNew.circle(x#,y#,r#=50,vx#=0,vy#=0) c.circle=New circle c\x=x c\y=y c\r=r c\vx=vx c\vy=vy CirclePlace(c) Return c End Function Function CirclePlace(c.circle,w#=800,h#=600) num=0 While CirclePlaceTest(c,c\x,c\y)=False And num<1000 c\x=Rnd(w) c\y=Rnd(h) num=num+1 Wend End Function ;Returns true if a circle can be placed, it doesn´t collide with any other circles or lines Function CirclePlaceTest(c.circle,x#,y#) For cc.circle=Each circle If cc<>c dx#=cc\x-c\x dy#=cc\y-c\y d#=Sqr(dx*dx+dy*dy) If d<(c\r+cc\r) Return False EndIf EndIf Next For l.cline=Each cline If LineCollide(l,c\x,c\y,c\r) Return False EndIf Next Return True End Function ;draw circles Function CircleDraw() Color 0,0,255 For c.circle=Each circle rh#=c\r*2 Oval c\x-c\r,c\y-c\r,rh,rh Next End Function Function CircleUpdate() For c.circle=Each circle ;Calculate total velocity c\vel#=Sqr(c\vx*c\vx+c\vy*c\vy) ;collision against other circles For cc.circle=Each circle ;do not test against itself If cc<>c ;vector from one circle to another dx#=cc\x-c\x dy#=cc\y-c\y d#=Sqr(dx*dx+dy*dy) ;check of distance is smaller than the two circle´s radii together If d<(c\r+cc\r) ;make the vector a unit vector (length=1), multiply it with the circle´s ;total velocity, to get the new motion vector c\vx=(-dx#/d) * c\vel c\vy=(-dy#/d) * c\vel EndIf EndIf Next ;collision agains lines For l.cline=Each cline ;Check if circle collides with a line If LineCollide(l,c\x,c\y,c\r) ;create a mark, where the circle has colliede with the line PoofNew(LineCollisionX,LineCollisionY) ;Get the dot product between the circles motion vector and the line´s normal vector dot#=c\vx*l\nx+c\vy*l\ny ;Calculate the circle´s new motion vector c\vx=c\vx-2.0*l\nx*dot c\vy=c\vy-2.0*l\ny*dot EndIf Next ;add velocity to position c\x=c\x+c\vx c\y=c\y+c\vy ;Wrap to screen boundaries If c\x>GraphicsWidth() c\x=0 EndIf If c\y>GraphicsHeight() c\y=0 EndIf If c\x<0 c\x=GraphicsWidth() EndIf If c\y<0 c\y=GraphicsHeight() EndIf Next End Function Type poof Field x,y Field age# Field maxage End Type Function PoofNew.poof(x,y,age#=20) p.poof=New poof p\x=x p\y=y p\maxage=age Return p End Function Function PoofUpdate() For p.poof=Each poof p\age=p\age+1 If p\age>=p\maxage Delete p EndIf Next End Function Function PoofDraw() For p.poof=Each poof pah=p\age*0.5 Oval p\x-pah,p\y-pah,p\age,p\age,0 Next End Function |
Comments
| ||
Hey, I like this alot! Great job :D The only problem I see is that you can get the balls to get stuck in the wall if you get them bouncing enough :O |
| ||
Nice one mate. Welldone and cheers :) |
| ||
Hi. These are some nice maths. I modified it so that you can only enter the line XY , circle XY and radius and call one function. It is simpler and better in some cases i think. Here is the code:;From original 2D Collision Example By Jeppe Nielsen 2004 ;Modified by Lenn (August 2005) Graphics 800,600,0,2 linex1#= 7 liney1# = 20 linex2#= 371 liney2# = 350 circlex#= 300 circley# = 200 circler# = 70 Line linex1, liney1, linex2, liney2 Oval circlex-circler, circley-circler, circler*2, circler*2 If LineToCircle( linex1, liney1, linex2, liney2, circlex, circley, circler) Then Text 10,100, "Collided." Else Text 10,100, "Not collided." End If WaitKey Function LineToCircle( lx1#, ly1#, lx2#, ly2#, cx#, cy#, r#) dx# = lx2 - lx1 dy# = ly2 - ly1 ld# = Sqr((dx*dx) + (dy*dy)) lux# = dx / ld luy# = dy / ld lnx# = luy lny# = -lux dx1# = cx - (lx1 - lux*r) dy1# = cy - (ly1 - luy*r) d# = Sqr((dx1*dx1) + (dy1*dy1)) dx1 = dx1 / d dy1 = dy1/ d dx2# = cx - (lx2 + lux * r) dy2# = cy - (ly2 + luy*r) d = Sqr((dx2*dx2) + (dy2*dy2)) dx2 = dx2 / d dy2 = dy2 / d dot1# = (dx1 * lux) + (dy1 * luy) dot2# = (dx2 * lux) + (dy2 * luy) px#=lx1-cx py#=ly1-cy distsq# = Abs((dx * py - px * dy) / ld ) ;You can get point of collision using these two variables (make them global) ;LineColX# = cx - lnx * sqr(distsq) ;LineColY# = cy - lny * sqr(distsq) Return (( dot1>=0 And dot2<=0) Or (dot1<=0 And dot2>=0)) And (distsq <= r) End Function Something to help the search engines: line to circle collisions circle to line collisions line circle collision circle line intersect line circle overlap |
| ||
It would be cool to have a Line vs. Line of Braincell's modification. :) |
Code Archives Forum