bmax physics engine

Miscellaneous Forums/Blitz Showcase/bmax physics engine

I've been working on this engine for quite a while now. it currently features:
circle-circle collisions
line-circle collisions
line-line collisions

the circle to circle and line to circle collisions are time based, meaning they won't pass over eachother when they are moving really fast. Line to line time based collisions are soon to come but my current idea for it is very slow.

will i release the source? If i get some complements or some constructive criticism ;) .

Theres still *a lot* of things i need to add, including documentation, even though the demo might seem near complete. Some of the things i need to add are:
>rolling balls
>making polygons seem non-hollow (they are joined lines)
>friction between circles and lines. think jumping on a moving platform and not moving with the platform.
>faster time based line-line collision
>a method to handle collisions between parralel lines

use WASD to move turret, mouse to aim, and click to fire. The balls are shot at 100 pixels per loop to test the time based collisions.
http://agogsoft.com/physics3.zip

Flounder, I can't get to the server for download.

Looks good.
About rolling balls I may sugest you to have a look at this : http://www.blitzmax.com/Community/posts.php?topic=55799
the ellipsoid always sliding but I think it can be tricked to bunce and slide.
Also it have very good intersection functions.
Be sure to read the original document.
For the boxies I thing you better give up the idea of the line-line collision and starting to learn about separetion axis and OBB ( oriented Bounding box . if I rember it right )
About Parrarel lines you must create a Global that will be your minnimum float calculation and check if the collision between the parralel line is lower of this otherwise you may get infinity numbers.

>making polygons seem non-hollow (they are joined lines)
this will work for circle but not for other shapes.

Does look good.
Ball is a bit quick to really check the collisions but some of them get inside the squares... Is that expected? Also, if you move the canon to the bottom left or right behind the 'wall' and fire a single bullet it will get stuck behind the wall with seemingly no way out. If you go mental on the fire button they begin to escape.
Not sure how this should be handled but seems to miss the collision.

It's not expected but the way the balls are reacting with each other looks good and the way the boxies are reacting when the collision it's right looks good.

SetGraphicsDriver GLMax2DDriver()

Graphics 800,600,32,60
SeedRnd MilliSecs()

Global linx:Float,liny:Float
Global lcx:Float,lcy:Float
Global cpx:Float,cpy:Float

Global fps_time:Float,fps_loop:Float,fps_fps:Float

Global world_group:group=group.Create(1)

Type group
	Global elasticity:Float=1
	
	Global group_list:TList=New TList
	
	Field circle_list:Tlist
	Field lyne_list:TList
	Field x:Float,y:Float
	Field width:Float,height:Float
	Field self_collisions:Int
	Field avoid_groups:TList
	
	Function Create:group(self_collisions:Int)
		g:group=New group
		g.self_collisions=self_collisions
		g.circle_list=New TList
		g.lyne_list=New TList
		g.avoid_groups=New TList
		group.group_list.AddLast g
		Return g
	EndFunction
	
	Function CollideCircles(c:point,cc:point,dist:Float=-1)
		Local x:Float=cc.x-c.x
		Local y:Float=cc.y-c.y
		If dist<0 Then dist=Sqr(x*x+y*y)
		If dist=0 Then dist=.0001
		x=x/dist
		y=y/dist
		If x=0 And y=0 Then x=1
		Local mass1:Float=cc.mass/(c.mass+cc.mass)
		Local mass2:Float=c.mass/(c.mass+cc.mass)
		Local offset:Float=(cc.r+c.r)-dist
		cc.x=cc.x+x*mass2*offset
		cc.y=cc.y+y*mass2*offset
		c.x=c.x-x*mass1*offset
		c.y=c.y-y*mass1*offset
		Local p:Float=(2.0*((c.xv*x+c.yv*y)-(cc.xv*x+cc.yv*y)))
		c.xv=c.xv-p*mass1*x
		c.yv=c.yv-p*mass1*y
		cc.xv=cc.xv+p*mass2*x
		cc.yv=cc.yv+p*mass2*y
	EndFunction
	
	Function CollideCircleLine(c:point,l:constraint,cr:Float=0)
		If cr<1 Then cr=c.r
		If LineCircle(l.a.x,l.a.y,l.b.x,l.b.y,c.x,c.y,cr)=1
			Local d:Float=Sqr((l.a.x-l.b.x)*(l.a.x-l.b.x)+(l.a.y-l.b.y)*(l.a.y-l.b.y))
			Local D0:Float=Sqr((l.a.x-lcx)*(l.a.x-lcx)+(l.a.y-lcy)*(l.a.y-lcy))
			'calculate the %'s of the masses and velocities based on where the point of contact is on each line
			Local p2:Float=D0/d
			If p2>1 Then p2=1
			Local p1:Float=1.0-p2
			Local tmass1:Float=p1*l.a.mass+p2*l.b.mass
			Local tvelx1:Float=p1*l.a.xv+p2*l.b.xv
			Local tvely1:Float=p1*l.a.yv+p2*l.b.yv
			If D0>d/2.0 Then D0=d-D0
			Local angle:Float=ATan2(lcy-c.y,lcx-c.x)+180
			Local angle1:Float=ATan2(c.y-lcy,c.x-lcx)+180
			'find the how much is crossing over the other line
			Local x:Float=Cos(angle)
			Local y:Float=Sin(angle)
			Local mass1:Float=c.mass/(tmass1+c.mass)
			Local mass2:Float=tmass1/(tmass1+c.mass)
			Local offset:Float=(cr-Sqr((lcx-c.x)*(lcx-c.x)+(lcy-c.y)*(lcy-c.y)))
			l.a.x=l.a.x-x*offset*p1*mass1
			l.a.y=l.a.y-y*offset*p1*mass1
			l.b.x=l.b.x-x*offset*p2*mass1
			l.b.y=l.b.y-y*offset*p2*mass1
			c.x=c.x+x*offset*mass2
			c.y=c.y+y*offset*mass2
			Local p:Float=((2.0*((tvelx1*x+tvely1*y)-(c.xv*x+c.yv*y)))/(tmass1+c.mass))
			tvelx1=-p*c.mass*x
			tvely1=-p*c.mass*y
			l.a.xv=l.a.xv+tvelx1*p1
			l.a.yv=l.a.yv+tvely1*p1
			l.b.xv=l.b.xv+tvelx1*p2
			l.b.yv=l.b.yv+tvely1*p2
			c.xv=c.xv+p*tmass1*x
			c.yv=c.yv+p*tmass1*y
			Return 1
		EndIf
		Return 0
	EndFunction
	
	Function CollideLines(l:constraint,ll:constraint)
		Local offset:Float,angle:Float,d5:Float,d6:Float
		Local d1:Float=(l.a.x-linx)*(l.a.x-linx)+(l.a.y-liny)*(l.a.y-liny)
		Local d2:Float=(l.b.x-linx)*(l.b.x-linx)+(l.b.y-liny)*(l.b.y-liny)
		If d2<d1
			d1=-1
			d5=d2
		Else
			d2=-1
			d5=d1
		EndIf
		Local d3:Float=(ll.a.x-linx)*(ll.a.x-linx)+(ll.a.y-liny)*(ll.a.y-liny)
		Local d4:Float=(ll.b.x-linx)*(ll.b.x-linx)+(ll.b.y-liny)*(ll.b.y-liny)
		If d4<d3
			d3=-1
			d6=d4
		Else
			d4=-1
			d6=d3
		EndIf
		If d5<d6
			If d1=-1
				ClosestPoint(ll.a.x,ll.a.y,ll.b.x,ll.b.y,l.b.x,l.b.y,0)
				offset=Sqr((l.b.x-cpx)*(l.b.x-cpx)+(l.b.y-cpy)*(l.b.y-cpy))*2.0
				angle=ATan2(l.b.y-cpy,l.b.x-cpx)+180
			Else
				ClosestPoint(ll.a.x,ll.a.y,ll.b.x,ll.b.y,l.a.x,l.a.y,0)
				offset=Sqr((l.a.x-cpx)*(l.a.x-cpx)+(l.a.y-cpy)*(l.a.y-cpy))*2.0
				angle=ATan2(l.a.y-cpy,l.a.x-cpx)+180
			EndIf
		Else
			If d3=-1
				ClosestPoint(l.a.x,l.a.y,l.b.x,l.b.y,ll.b.x,ll.b.y,0)
				offset=Sqr((ll.b.x-cpx)*(ll.b.x-cpx)+(ll.b.y-cpy)*(ll.b.y-cpy))*2.0
				angle=ATan2(ll.b.y-cpy,ll.b.x-cpx)'+180
			Else
				ClosestPoint(l.a.x,l.a.y,l.b.x,l.b.y,ll.a.x,ll.a.y,0)
				offset=Sqr((ll.a.x-cpx)*(ll.a.x-cpx)+(ll.a.y-cpy)*(ll.a.y-cpy))*2.0
				angle=ATan2(ll.a.y-cpy,ll.a.x-cpx)'+180
			EndIf
		EndIf
		angle=angle+180.0
		Local lind0:Float=Sqr((l.a.x-l.b.x)*(l.a.x-l.b.x)+(l.a.y-l.b.y)*(l.a.y-l.b.y))
		Local lind1:Float=Sqr((ll.a.x-ll.b.x)*(ll.a.x-ll.b.x)+(ll.a.y-ll.b.y)*(ll.a.y-ll.b.y))
		d1=Sqr((l.a.x-linx)*(l.a.x-linx)+(l.a.y-liny)*(l.a.y-liny))
		d2=Sqr((ll.a.x-linx)*(ll.a.x-linx)+(ll.a.y-liny)*(ll.a.y-liny))
		'calculate the %'s of the masses and velocities based on where the point of contact is on each line
		Local p2:Float=d1/lind0
		Local p1:Float=1.0-p2
		Local p4:Float=d2/lind1
		Local p3:Float=1.0-p4
		'see if the first point has a velocity
		Local tmass1:Float=p1*l.a.mass+p2*l.b.mass
		Local tmass2:Float=p3*ll.a.mass+p4*ll.b.mass
		Local tvelx1:Float=p1*l.a.xv+p2*l.b.xv
		Local tvely1:Float=p1*l.a.yv+p2*l.b.yv
		Local tvelx2:Float=p3*ll.a.xv+p4*ll.b.xv
		Local tvely2:Float=p3*ll.a.yv+p4*ll.b.yv
		Local x:Float=Cos(angle)
		Local y:Float=Sin(angle)
		Local mass1:Float=tmass2/(tmass1+tmass2)
		Local mass2:Float=tmass1/(tmass1+tmass2)
		l.a.x=l.a.x-x*offset*p1*mass1
		l.a.y=l.a.y-y*offset*p1*mass1
		l.b.x=l.b.x-x*offset*p2*mass1
		l.b.y=l.b.y-y*offset*p2*mass1
		ll.a.x=ll.a.x+x*offset*p3*mass2
		ll.a.y=ll.a.y+y*offset*p3*mass2
		ll.b.x=ll.b.x+x*offset*p4*mass2
		ll.b.y=ll.b.y+y*offset*p4*mass2
		Local v1:Float=tvelx1*x+tvely1*y
		Local v2:Float=tvelx2*x+tvely2*y
		Local p:Float=(2.0*(v1-v2))/(tmass1+tmass2)
		tvelx1=p*tmass2*x
		tvely1=p*tmass2*y
		tvelx2=p*tmass1*x
		tvely2=p*tmass1*y
		l.a.xv=l.a.xv-tvelx1*p1
		l.a.yv=l.a.yv-tvely1*p1
		l.b.xv=l.b.xv-tvelx1*p2
		l.b.yv=l.b.yv-tvely1*p2
		ll.a.xv=ll.a.xv+tvelx2*p3
		ll.a.yv=ll.a.yv+tvely2*p3
		ll.b.xv=ll.b.xv+tvelx2*p4
		ll.b.yv=ll.b.yv+tvely2*p4
	EndFunction
	
	Function predict:Float(x0:Float,y0:Float,x1:Float,y1:Float,xv0:Float,yv0:Float,xv1:Float,yv1:Float,cr:Float)
		'thanks to daftabrush @gamedev.net for this detection method!
		'get the distance of the line
		Local d:Float=Sqr((x0-x1)*(x0-x1)+(y0-y1)*(y0-y1))
		If d=0 Then d=.0001
		Local a:Float=((xv1-xv0)*(-yv0)-(yv1-yv0)*(-xv0))/d
		Local b:Float=((x1-x0)*(-yv0)+(-y0)*(xv1-xv0)+(y0-y1)*(-xv0)+(x0)*(yv1-yv0))/d
		' Lose the -cr from the c1 calculation initially
		Local c:Float=((x1-x0)*(-y0)+(y0-y1)*(-x0))/d
		' The check the sign of the Cross-product
		If c>=0
		' Cross-Product is +ve or zero
			c=c-cr+1 ' subtract cr
		Else
		' Cross-Product is Negative
			c=c+cr-1 ' add cr instead
		EndIf
		Local t:Float=0
		Local root:Float=b*b-4.0*a*c
		If root>0 Or a=0 'they might collide
			b=0.0-b
			If a=0
				t=c/b
			Else
				root=Sqr(root)
				t=(b+root)/(2*a)
				Local t1:Float=(b-root)/(2*a)
				If t<0 Or t>1
					t=t1
				ElseIf t1>0 And t1<1 And t1<t
					t=t1
				EndIf
			EndIf
			Return t
		EndIf
		Return -1		
	EndFunction
	
	Function Update()
		Local g:group,gg:group
		Local cc:point,c:point
		Local l:constraint,ll:constraint
		Local is_first_coord:Int=0
		Local max_d:Float,D0:Float,D1:Float,t:Float,x:Float,y:Float,x0:Float,y0:Float,x1:Float,y1:Float,d:Float
		For g=EachIn group.group_list
			is_first_coord=0
			g.x=0
			g.y=0
			g.width=0
			g.height=0
			For c=EachIn g.circle_list
				If is_first_coord=0
					is_first_coord=1
					g.x=c.x-c.r
					g.y=c.y-c.r
					g.width=c.x+c.r
					g.height=c.y+c.r
				EndIf
				If c.x+c.xv*(c.xv<0)-c.r<g.x Then g.x=c.x+c.xv*(c.xv<0)-c.r
				If c.y+c.yv*(c.yv<0)-c.r<g.y Then g.y=c.y+c.yv*(c.yv<0)-c.r
				If c.x+c.xv*(c.xv>0)+c.r>g.width Then g.width=c.x+c.xv*(c.xv>0)+c.r
				If c.y+c.yv*(c.yv>0)+c.r>g.height Then g.height=c.y+c.yv*(c.yv>0)+c.r
			Next
			For l=EachIn g.lyne_list
				If is_first_coord=0
					is_first_coord=1
					g.x=l.a.x-l.a.r
					g.y=l.a.y-l.a.r
					g.width=l.a.x+l.a.r
					g.height=l.a.y+l.a.r
				EndIf
				If l.a.x+l.a.xv*(l.a.xv<0)-l.a.r<g.x Then g.x=l.a.x+l.a.xv*(l.a.xv<0)-l.a.r
				If l.a.y+l.a.yv*(l.a.yv<0)-l.a.r<g.y Then g.y=l.a.y+l.a.yv*(l.a.yv<0)-l.a.r
				If l.a.x+l.a.xv*(l.a.xv>0)+l.a.r>g.width Then g.width=l.a.x+l.a.xv*(l.a.xv>0)+l.a.r
				If l.a.y+l.a.yv*(l.a.yv>0)+l.a.r>g.height Then g.height=l.a.y+l.a.yv*(l.a.yv>0)+l.a.r
				If l.b.x+l.b.xv*(l.b.xv<0)-l.b.r<g.x Then g.x=l.b.x+l.b.xv*(l.b.xv<0)-l.b.r
				If l.b.y+l.b.yv*(l.b.yv<0)-l.b.r<g.y Then g.y=l.b.y+l.b.yv*(l.b.yv<0)-l.b.r
				If l.b.x+l.b.xv*(l.b.xv>0)+l.b.r>g.width Then g.width=l.b.x+l.b.xv*(l.b.xv>0)+l.b.r
				If l.b.y+l.b.yv*(l.b.yv>0)+l.b.r>g.height Then g.height=l.b.y+l.b.yv*(l.b.yv>0)+l.b.r
			Next
			g.width=g.width-g.x+1
			g.height=g.height-g.y+1
			'rect2(g.x,g.y,g.width,g.height,1)
		Next
		Local col_circle:circle_col
		Local t1:Float,t2:Float,t3:Float,t4:Float
		Local mass1:Float,mass2:Float
		Local p1:Float,p2:Float,tmass1:Float,tvelx1:Float,tvely1:Float,angle:Float,angle1:Float,offset:Float,p:Float
		Local self_collisions:Int
		Local xv0:Float,yv0:Float,xv1:Float,yv1:Float,xv:Float,yv:Float
		Local lp0:Int,lp1:Int
		For g=EachIn group.group_list
			self_collisions=0
			If g.self_collisions=1
				gg=g
				self_collisions=1
			Else
				gg=g.After()
			EndIf
			While gg
				'if the 2 groups are colliding
				If rectoverlap(g.x,g.y,g.width,g.height,gg.x,gg.y,gg.width,gg.height)=1
					For c=EachIn g.circle_list
						'loop through the circles in the other group
						If self_collisions=1
							cc=c.After()
						Else
							cc=point(gg.circle_list.First())
						EndIf
						While cc
							'the distance between the circles
							D0=Sqr((c.x-cc.x)*(c.x-cc.x)+(c.y-cc.y)*(c.y-cc.y))
							max_d=c.r+cc.r
							If D0<max_d
								'they are hitting eachother
								group.CollideCircles(c,cc,D0)
							Else
								x0=cc.xv*cc.p*cc.fx
								y0=cc.yv*cc.p*cc.fy
								x1=c.xv*c.p*c.fx-x0
								y1=c.yv*c.p*c.fy-y0
								'see if they might collide
								D1=(x1*x1)+(y1*y1)'(c.xv*c.p-cc.xv*cc.p)*(c.xv*c.p-cc.xv*cc.p)+(c.yv*c.p-cc.yv*cc.p)*(c.yv*c.p-cc.yv*cc.p)
								'if they are moving
								If D1>0
									D1=Sqr(D1)
									'the time of collision
									t=(D0-max_d)/D1
									If t<1
										'the new positions
										x0=cc.x+cc.xv*t*cc.p*cc.fx
										y0=cc.y+cc.yv*t*cc.p*cc.fy
										x1=c.x+c.xv*t*c.p*c.fx
										y1=c.y+c.yv*t*c.p*c.fy
										'double check if theres a gap
										D0=Sqr((x0-x1)*(x0-x1)+(y0-y1)*(y0-y1))
										t=t+2.0*(D0-max_d+1)/D1
										If t>1 Then t=1
										x0=cc.x+cc.xv*t*cc.p
										y0=cc.y+cc.yv*t*cc.p*cc.fy
										x1=c.x+c.xv*t*c.p*c.fx
										y1=c.y+c.yv*t*c.p*c.fy
										If (x0-x1)*(x0-x1)+(y0-y1)*(y0-y1)<max_d*max_d
											'it will collide if nothing else hits it
											'add it to the list based on its time
											circle_col.AddCol(t,cc)
										EndIf
									EndIf
								EndIf
								'if they can push eachother
								If D0<max_d+c.push_rad And c.push_rad>0
									'they can
									'get the distances from the edge of the circles
									D0=Sqr((c.x-cc.x)*(c.x-cc.x)+(c.y-cc.y)*(c.y-cc.y))-max_d
									mass1=cc.mass/(c.mass+cc.mass)
									mass2=c.mass/(c.mass+cc.mass)
									If D0=0 Then D0=.0001
									d=(1.0-D0/c.push_rad)*c.push
									x=(cc.x-c.x)/D0
									y=(cc.y-c.y)/D0
									If x=0 And y=0 Then x=1
									c.xv=c.xv-x*mass1*d
									c.yv=c.yv-y*mass1*d
									cc.xv=cc.xv+x*mass2*d
									cc.yv=cc.yv+y*mass2*d
								EndIf
							EndIf
							'move to the next circle
							cc=cc.After()
						Wend
						'loop through the lines in that group
						For l=EachIn gg.lyne_list
							'is the circle not one of the end points of the line
							If c<>l.a And c<>l.b' Then CollideCircleLine(c,l)
								If CollideCircleLine(c,l)=0
									xv=c.xv*c.fx*c.p
									yv=c.yv*c.fy*c.p
									xv0=l.a.xv*l.a.fx*l.a.p-xv
									yv0=l.a.yv*l.a.fy*l.a.p-yv
									xv1=l.b.xv*l.b.fx*l.b.p-xv
									yv1=l.b.yv*l.b.fy*l.b.p-yv
									t=group.predict(l.a.x-c.x,l.a.y-c.y,l.b.x-c.x,l.b.y-c.y,xv0,yv0,xv1,yv1,c.r)
									If t>0 And t<1 'is it within 1 timestep
										x0=l.a.x+l.a.xv*t*l.a.p*l.a.fx
										y0=l.a.y+l.a.yv*t*l.a.p*l.a.fy
										x1=l.b.x+l.b.xv*t*l.b.p*l.b.fx
										y1=l.b.y+l.b.yv*t*l.b.p*l.b.fy
										x=c.x+c.xv*c.fx*c.p*t
										y=c.y+c.yv*c.fy*c.p*t
										'do they overlap
										If LineCircle(x0,y0,x1,y1,x,y,c.r)
											circle_col.AddLyne(t,l)
										EndIf
									EndIf
								EndIf
							EndIf
						Next
						'is the any collisions to check
						'check if they still collide
						For col_circle=EachIn circle_col.circle_col_list
							'is it a circle collision
							If col_circle.is_lyne=0
								cc=col_circle.a
								'get the distance
								D0=Sqr((c.x-cc.x)*(c.x-cc.x)+(c.y-cc.y)*(c.y-cc.y))
								max_d=c.r+cc.r
								'are they already colliding
								If D0<max_d
									group.CollideCircles(c,cc,D0)
								Else
									x0=cc.xv*cc.p*cc.fx
									y0=cc.yv*cc.p*cc.fy
									x1=c.xv*c.p*c.fx-x0
									y1=c.yv*c.p*c.fy-y0
									'is it still within 1 timestep
									D1=(x1*x1)+(y1*y1)'D1=(c.xv*c.p-cc.xv*cc.p)*(c.xv*c.p-cc.xv*cc.p)+(c.yv*c.p-cc.yv*cc.p)*(c.yv*c.p-cc.yv*cc.p)
									'is it moving
									If D1>0
										D1=Sqr(D1)
										'the time
										t=(D0-max_d)/D1
										'is it still within 1 timestep
										If t<=1 And t>0
											'calc the new positions
											x0=cc.x+cc.xv*t*cc.p*cc.fx
											y0=cc.y+cc.yv*t*cc.p*cc.fy
											x1=c.x+c.xv*t*c.p*c.fx
											y1=c.y+c.yv*t*c.p*c.fy
											'double check if theres a gap
											D0=Sqr((x0-x1)*(x0-x1)+(y0-y1)*(y0-y1))
											t=t+2.0*(D0-max_d+1)/D1
											If t>1 Then t=1
											x0=cc.x+cc.xv*t*cc.p*cc.fx
											y0=cc.y+cc.yv*t*cc.p*cc.fy
											x1=c.x+c.xv*t*c.p*c.fx
											y1=c.y+c.yv*t*c.p*c.fy
											'are they colliding
											D0=(x0-x1)*(x0-x1)+(y0-y1)*(y0-y1)
											If D0<max_d*max_d
												cc.x=x0
												cc.y=y0
												c.x=x1
												c.y=y1
												c.p=c.p-c.p*t
												If c.p<0 Then c.p=0
												cc.p=cc.p-cc.p*t
												If cc.p<0 Then cc.p=0
												group.CollideCircles(c,cc,Sqr(D0))
											EndIf
										EndIf
									EndIf
								EndIf
							'is it a line
							ElseIf col_circle.is_lyne=1
								l=col_circle.b
								'are they already colliding
								If CollideCircleLine(c,l)=0
									xv=c.xv*c.fx*c.p
									yv=c.yv*c.fy*c.p
									xv0=l.a.xv*l.a.fx*l.a.p-xv
									yv0=l.a.yv*l.a.fy*l.a.p-yv
									xv1=l.b.xv*l.b.fx*l.b.p-xv
									yv1=l.b.yv*l.b.fy*l.b.p-yv
									t=group.predict(l.a.x-c.x,l.a.y-c.y,l.b.x-c.x,l.b.y-c.y,xv0,yv0,xv1,yv1,c.r)
									If t>0 And t<1 'is it within 1 timestep
										x0=l.a.x+l.a.xv*t*l.a.p*l.a.fx
										y0=l.a.y+l.a.yv*t*l.a.p*l.a.fy
										x1=l.b.x+l.b.xv*t*l.b.p*l.b.fx
										y1=l.b.y+l.b.yv*t*l.b.p*l.b.fy
										x=c.x+c.xv*c.fx*c.p*t
										y=c.y+c.yv*c.fy*c.p*t
										'do they overlap
										If LineCircle(x0,y0,x1,y1,x,y,c.r)
											l.a.x=x0
											l.a.y=y0
											l.b.x=x1
											l.b.y=y1
											c.x=x
											c.y=y
											c.p=c.p-c.p*t
											If c.p<0 Then c.p=0
											l.a.p=l.a.p-l.a.p*t
											If l.a.p<0 Then l.a.p=0
											l.b.p=l.b.p-l.b.p*t
											If l.b.p<0 Then l.b.p=0
											group.CollideCircleLine(c,l)
										EndIf
									EndIf
								EndIf
							EndIf
						Next
						'clear all the attempted collisions
						ClearList(circle_col.circle_col_list)
					Next
					'loop through the lines
					For l=EachIn g.lyne_list
						If self_collisions=0
							'is the circle not one of the end points of the line
							For c=EachIn gg.circle_list
								If c<>l.a And c<>l.b' Then CollideCircleLine(c,l)
									If CollideCircleLine(c,l)=0
										xv=c.xv*c.fx*c.p
										yv=c.yv*c.fy*c.p
										xv0=l.a.xv*l.a.fx*l.a.p-xv
										yv0=l.a.yv*l.a.fy*l.a.p-yv
										xv1=l.b.xv*l.b.fx*l.b.p-xv
										yv1=l.b.yv*l.b.fy*l.b.p-yv
										x0=l.a.x-c.x
										y0=l.a.y-c.y
										x1=l.b.x-c.x
										y1=l.b.y-c.y
										t=group.predict(x0,y0,x1,y1,xv0,yv0,xv1,yv1,c.r)
										If t>0 And t<1 'is it within 1 timestep
											x0=l.a.x+l.a.xv*t*l.a.p*l.a.fx
											y0=l.a.y+l.a.yv*t*l.a.p*l.a.fy
											x1=l.b.x+l.b.xv*t*l.b.p*l.b.fx
											y1=l.b.y+l.b.yv*t*l.b.p*l.b.fy
											x=c.x+c.xv*c.fx*c.p*t
											y=c.y+c.yv*c.fy*c.p*t
											'do they overlap
											If LineCircle(x0,y0,x1,y1,x,y,c.r)
												circle_col.AddCol(t,c)
											EndIf
										EndIf
									EndIf
								EndIf
							Next
						EndIf
						If self_collisions=1
							ll=l.After()
						Else
							ll=constraint(gg.lyne_list.First())
						EndIf
						While ll
							'make sure they don't share a point
							If ll.a<>l.a And ll.b<>l.a And ll.a<>l.b And ll.b<>l.b
								If LinesCross(l.a.x,l.a.y,l.b.x,l.b.y,ll.a.x,ll.a.y,ll.b.x,ll.b.y)=1
									CollideLines(l,ll)
								Else
									'do a point collide check
									Rem
								'----------------------------------------------
									'the first point of the 1st line
									xv=l.a.xv*l.a.fx*l.a.p
									yv=l.a.yv*l.a.fy*l.a.p
									xv0=ll.a.xv*ll.a.fx*ll.a.p-xv
									yv0=ll.a.yv*ll.a.fy*ll.a.p-yv
									xv1=ll.b.xv*ll.b.fx*ll.b.p-xv
									yv1=ll.b.yv*ll.b.fy*ll.b.p-yv
									x0=ll.a.x-l.a.x
									y0=ll.a.y-l.a.y
									x1=ll.b.x-l.a.x
									y1=ll.b.y-l.a.y
									t1=predict(x0,y0,x1,y1,xv0,yv0,xv1,yv1,2)
									'the second point of the 1st line
									xv=l.b.xv*l.b.fx*l.b.p
									yv=l.b.yv*l.b.fy*l.b.p
									xv0=ll.a.xv*ll.a.fx*ll.a.p-xv
									yv0=ll.a.yv*ll.a.fy*ll.a.p-yv
									xv1=ll.b.xv*ll.b.fx*ll.b.p-xv
									yv1=ll.b.yv*ll.b.fy*ll.b.p-yv
									x0=ll.a.x-l.b.x
									y0=ll.a.y-l.b.y
									x1=ll.b.x-l.b.x
									y1=ll.b.y-l.b.y
									t2=predict(x0,y0,x1,y1,xv0,yv0,xv1,yv1,2)
									t=t1
									If t1<0 Or t1>1
										t=t2
									ElseIf t2>0 And t2<1 And t2<t1
										t=t2
									EndIf
								'----------------------------------------------
									'the first point of the 2nd line
									xv=ll.a.xv*ll.a.fx*ll.a.p
									yv=ll.a.yv*ll.a.fy*ll.a.p
									xv0=l.a.xv*l.a.fx*l.a.p-xv
									yv0=l.a.yv*l.a.fy*l.a.p-yv
									xv1=l.b.xv*l.b.fx*l.b.p-xv
									yv1=l.b.yv*l.b.fy*l.b.p-yv
									x0=l.a.x-ll.a.x
									y0=l.a.y-ll.a.y
									x1=l.b.x-ll.a.x
									y1=l.b.y-ll.a.y
									t3=predict(x0,y0,x1,y1,xv0,yv0,xv1,yv1,2)
									'the second point of the 2nd line
									xv=ll.b.xv*ll.b.fx*ll.b.p
									yv=ll.b.yv*ll.b.fy*ll.b.p
									xv0=l.a.xv*l.a.fx*l.a.p-xv
									yv0=l.a.yv*l.a.fy*l.a.p-yv
									xv1=l.b.xv*l.b.fx*l.b.p-xv
									yv1=l.b.yv*l.b.fy*l.b.p-yv
									x0=l.a.x-ll.b.x
									y0=l.a.y-ll.b.y
									x1=l.b.x-ll.b.x
									y1=l.b.y-ll.b.y
									t4=predict(x0,y0,x1,y1,xv0,yv0,xv1,yv1,2)
									t1=t3
									If t3<0 Or t3>1
										t1=t4
									ElseIf t4>0 And t4<1 And t4<t3
										t1=t4
									EndIf
								'----------------------------------------------
									If t<0 Or t>1
										t=t1
									ElseIf t1>0 And t1<1 And t1<t
										t=t1
									EndIf
									If t>=0 And t<1
										circle_col.AddLyne(t,ll)
									EndIf
									EndRem
								EndIf
							EndIf
							ll=ll.After()
						Wend
						'is the any collisions to check
						'check if they still collide
						For col_circle=EachIn circle_col.circle_col_list
							If col_circle.is_lyne=1
								c=col_circle.a
								'are they already colliding
								If CollideCircleLine(c,l)=0
									xv=c.xv*c.fx*c.p
									yv=c.yv*c.fy*c.p
									xv0=l.a.xv*l.a.fx*l.a.p-xv
									yv0=l.a.yv*l.a.fy*l.a.p-yv
									xv1=l.b.xv*l.b.fx*l.b.p-xv
									yv1=l.b.yv*l.b.fy*l.b.p-yv
									x0=l.a.x-c.x
									y0=l.a.y-c.y
									x1=l.b.x-c.x
									y1=l.b.y-c.y
									t=group.predict(x0,y0,x1,y1,xv0,yv0,xv1,yv1,c.r)
									If t>0 And t<1 'is it within 1 timestep
										x0=l.a.x+l.a.xv*t*l.a.p*l.a.fx
										y0=l.a.y+l.a.yv*t*l.a.p*l.a.fy
										x1=l.b.x+l.b.xv*t*l.b.p*l.b.fx
										y1=l.b.y+l.b.yv*t*l.b.p*l.b.fy
										x=c.x+c.xv*c.fx*c.p*t
										y=c.y+c.yv*c.fy*c.p*t
										'do they overlap
										If LineCircle(x0,y0,x1,y1,x,y,c.r)
											l.a.x=x0
											l.a.y=y0
											l.b.x=x1
											l.b.y=y1
											c.x=x
											c.y=y
											c.p=c.p-c.p*t
											If c.p<0 Then c.p=0
											l.a.p=l.a.p-l.a.p*t
											If l.a.p<0 Then l.a.p=0
											l.b.p=l.b.p-l.b.p*t
											If l.b.p<0 Then l.b.p=0
											group.CollideCircleLine(c,l)
										EndIf
									EndIf
								EndIf
							Else'its a line
								'the first point of the 2nd line
								ll=col_circle.b
								If LinesCross(l.a.x,l.a.y,l.b.x,l.b.y,ll.a.x,ll.a.y,ll.b.x,ll.b.y)=1
									CollideLines(l,ll)
								Else
								Rem
										'do a point collide check
								'----------------------------------------------
									'the first point of the 1st line
									xv=l.a.xv*l.a.fx*l.a.p
									yv=l.a.yv*l.a.fy*l.a.p
									xv0=ll.a.xv*ll.a.fx*ll.a.p-xv
									yv0=ll.a.yv*ll.a.fy*ll.a.p-yv
									xv1=ll.b.xv*ll.b.fx*ll.b.p-xv
									yv1=ll.b.yv*ll.b.fy*ll.b.p-yv
									x0=ll.a.x-l.a.x
									y0=ll.a.y-l.a.y
									x1=ll.b.x-l.a.x
									y1=ll.b.y-l.a.y
									t1=predict(x0,y0,x1,y1,xv0,yv0,xv1,yv1,2)
									'the second point of the 1st line
									xv=l.b.xv*l.b.fx*l.b.p
									yv=l.b.yv*l.b.fy*l.b.p
									xv0=ll.a.xv*ll.a.fx*ll.a.p-xv
									yv0=ll.a.yv*ll.a.fy*ll.a.p-yv
									xv1=ll.b.xv*ll.b.fx*ll.b.p-xv
									yv1=ll.b.yv*ll.b.fy*ll.b.p-yv
									x0=ll.a.x-l.b.x
									y0=ll.a.y-l.b.y
									x1=ll.b.x-l.b.x
									y1=ll.b.y-l.b.y
									t2=predict(x0,y0,x1,y1,xv0,yv0,xv1,yv1,2)
									t=t1
									c=Null
									If t1>=0 And t1<1 Then c=ll.a
									If t1<0 Or t1>1
										t=t2
										c=ll.b
									ElseIf t2>0 And t2<1 And t2<t1
										t=t2
										c=ll.b
									EndIf
								'----------------------------------------------
									'the first point of the 2nd line
									xv=ll.a.xv*ll.a.fx*ll.a.p
									yv=ll.a.yv*ll.a.fy*ll.a.p
									xv0=l.a.xv*l.a.fx*l.a.p-xv
									yv0=l.a.yv*l.a.fy*l.a.p-yv
									xv1=l.b.xv*l.b.fx*l.b.p-xv
									yv1=l.b.yv*l.b.fy*l.b.p-yv
									x0=l.a.x-ll.a.x
									y0=l.a.y-ll.a.y
									x1=l.b.x-ll.a.x
									y1=l.b.y-ll.a.y
									t3=predict(x0,y0,x1,y1,xv0,yv0,xv1,yv1,2)
									'the second point of the 2nd line
									xv=ll.b.xv*ll.b.fx*ll.b.p
									yv=ll.b.yv*ll.b.fy*ll.b.p
									xv0=l.a.xv*l.a.fx*l.a.p-xv
									yv0=l.a.yv*l.a.fy*l.a.p-yv
									xv1=l.b.xv*l.b.fx*l.b.p-xv
									yv1=l.b.yv*l.b.fy*l.b.p-yv
									x0=l.a.x-ll.b.x
									y0=l.a.y-ll.b.y
									x1=l.b.x-ll.b.x
									y1=l.b.y-ll.b.y
									t4=predict(x0,y0,x1,y1,xv0,yv0,xv1,yv1,2)
									t1=t3
									cc=Null
									If t3>=0 And t3<1 Then cc=l.a
									If t3<0 Or t3>1
										t1=t4
										cc=l.b
									ElseIf t4>0 And t4<1 And t4<t3
										t1=t4
										cc=l.b
									EndIf
								'----------------------------------------------
									If t<0 Or t>1
										t=t1
										c=Null
									ElseIf t1>=0 And t1<1 And t1<t
										t=t1
										c=Null
									EndIf
									If t>=0 And t<1
										x0=l.a.x+l.a.xv*l.a.fx*l.a.p*t
										y0=l.a.y+l.a.yv*l.a.fy*l.a.p*t
										x1=l.b.x+l.b.xv*l.b.fx*l.b.p*t
										y1=l.b.y+l.b.yv*l.b.fy*l.b.p*t
										xv0=ll.a.x+ll.a.xv*ll.a.fx*ll.a.p*t
										yv0=ll.a.y+ll.a.yv*ll.a.fy*ll.a.p*t
										xv1=ll.b.x+ll.b.xv*ll.b.fx*ll.b.p*t
										yv1=ll.b.y+ll.b.yv*ll.b.fy*ll.b.p*t
										If c=Null Then c=cc
										If c<>Null
											Local ok:Int
											If c=l.a Or c=l.b
												ok=LineCircle(xv0,yv0,xv1,yv1,c.x,c.y,2)
											Else
												ok=LineCircle(x0,y0,x1,y1,c.x,c.y,2)
											EndIf
											If ok=1
											'If LinesCross(x0,y0,x1,y1,xv0,yv0,xv1,yv1)=1
												l.a.x=x0
												l.a.y=y0
												l.b.x=x1
												l.b.y=y1
												ll.a.x=xv0
												ll.a.y=yv0
												ll.b.x=xv1
												ll.b.y=yv1
												l.a.p=l.a.p-l.a.p*t
												If l.a.p<0 Then l.a.p=0
												l.b.p=l.b.p-l.b.p*t
												If l.b.p<0 Then l.b.p=0
												ll.a.p=ll.a.p-ll.a.p*t
												If ll.a.p<0 Then ll.a.p=0
												ll.b.p=ll.b.p-ll.b.p*t
												If ll.b.p<0 Then ll.b.p=0
												If c=l.a Or c=l.b
													group.CollideCircleLine(c,ll,2)
												Else
													group.CollideCircleLine(c,l,2)
												EndIf
											EndIf
										EndIf
									EndIf
									EndRem
								EndIf
							EndIf
						Next
						'clear all the attempted collisions
						ClearList(circle_col.circle_col_list)
					Next
				EndIf
				gg=gg.After()
			Wend
		Next
	EndFunction
	
	Method After:group()
		Local link:TLink=group_list.FindLink(Self).NextLink()
		If link Then Return group(link.Value())
		Return Null
	EndMethod
EndType

Type point
	Global point_list:TList=New TList

	Field x:Float,y:Float
	Field xv:Float,yv:Float
	Field fx:Float,fy:Float
	Field r:Float
	Field mass:Float
	Field p:Float
	Field push:Float,push_rad:Float
	Field in_group:group=Null
	Field spin:Float,angle:Float,grip:Float=1
	
	Function Create:point(x:Float,y:Float,xv:Float,yv:Float,fx:Float,fy:Float,r:Float,mass:Float,push:Float,push_rad:Float,in_group:group=Null)
		Local p:point=New point
		p.x=x
		p.y=y
		p.xv=xv
		p.yv=yv
		p.fx=fx
		p.fy=fy
		p.push=push
		p.push_rad=push_rad
		p.r=r
		If p.r>0
			If in_group=Null Then in_group=world_group
			p.in_group=in_group
			in_group.circle_list.Addlast p
		EndIf
		p.mass=mass
		p.p=1
		point_list.AddLast p
		Return p
	EndFunction
	
	Function UpdatePoints()
		SetBlend LIGHTBLEND
		For p:point=EachIn point_list
			p.yv=p.yv+.2
			p.xv=p.xv*p.fx
			p.yv=p.yv*p.fy
			p.x=p.x+p.xv*p.p
			p.y=p.y+p.yv*p.p
			p.p=1
			SetColor 255,255,255
			SetAlpha 1
			oval2(p.x-p.r,p.y-p.r,p.r*2.0,p.r*2.0,0)
			p.angle=p.angle+p.spin
			DrawLine p.x,p.y,p.x+Cos(angle)*p.r,p.y+Sin(angle)*p.r
			SetColor 255,0,0
			SetAlpha .25
			oval2(p.x-p.r-p.push_rad,p.y-p.r-p.push_rad,(p.r+p.push_rad)*2,(p.r+p.push_rad)*2,1)
			If p.x<p.r
				p.x=p.r
				p.xv=-p.xv
			EndIf
			If p.y<p.r
				p.y=p.r
				p.yv=-p.yv
			EndIf
			If p.x>800-p.r
				p.x=800-p.r
				p.xv=-p.xv
			EndIf
			If p.y>600-p.r
				p.y=600-p.r
				p.yv=-p.yv
			EndIf
		Next
	EndFunction
	
	Method After:point()
		Local link:TLink=in_group.circle_list.FindLink(Self).NextLink()
		If link Then Return point(link.Value())
		Return Null
	EndMethod
EndType

Type circle_col
	Global circle_col_list:TList=New TList
	Field t:Float
	Field a:point
	Field b:constraint
	Field is_lyne:Int
	
	Function AddLyne:circle_col(t:Float,b:constraint)
		c:circle_col=New circle_col
		c.t=t
		c.b=b
		c.is_lyne=1
		If circle_col_list=Null
			circle_col_list.AddLast c
		Else
			Local cc:circle_col
			Local added:Int=0
			For cc=EachIn circle_col.circle_col_list
				If t<cc.t
					circle_col_list.InsertBeforeLink(c,circle_col_list.FindLink(cc))
					added=1
					Exit
				EndIf
			Next
			If added=0
				circle_col_list.AddLast c
			EndIf
		EndIf
		Return c
	End Function
	
	Function AddCol:circle_col(t:Float,a:point)
		c:circle_col=New circle_col
		c.t=t
		c.a=a
		If circle_col_list=Null
			circle_col_list.AddLast c
		Else
			Local cc:circle_col
			Local added:Int=0
			For cc=EachIn circle_col.circle_col_list
				If t<cc.t
					circle_col_list.InsertBeforeLink(c,circle_col_list.FindLink(cc))
					added=1
					Exit
				EndIf
			Next
			If added=0
				circle_col_list.AddLast c
			EndIf
		EndIf
		Return c
	EndFunction
	Method Before:circle_col()
		Local link:TLink=circle_col_list.FindLink(Self).PrevLink()
		If link Then Return circle_col(link.Value())
		Return Null
	EndMethod
	Method After:circle_col()
		Local link:TLink=circle_col_list.FindLink(Self).NextLink()
		If link Then Return circle_col(link.Value())
		Return Null
	EndMethod
EndType

Type constraint
	Global constraint_list:TList=New TList
	
	Field a:point
	Field b:point
	Field dist:Float
	Field tension:Float
	Field in_group:group=Null
	Field minimum:Float,maximum:Float
	
	Function Create:constraint(a:point,b:point,dist:Float,tension:Float,minimum:Float,maximum:Float,is_lyne:Int,in_group:group=Null)
		c:constraint=New constraint
		c.a=a
		c.b=b
		c.dist=dist
		c.minimum=minimum
		c.maximum=maximum
		If c.dist<0 Then c.dist=Sqr((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y))
		c.tension=tension
		If is_lyne=1
			If in_group=Null Then in_group=world_group
			c.in_group=in_group
			in_group.lyne_list.Addlast c
		EndIf
		constraint_list.Addlast c
		Return c
	End Function
	
	Function UpdateConstraints()
		Local c:constraint
		Local x:Float,y:Float
		Local diff:Float
		Local mass1:Float,mass2:Float
		Local dist:Float
		For c=EachIn constraint.constraint_list
			x=c.a.x-c.b.x
			y=c.a.y-c.b.y
			dist=Sqr(x*x+y*y)
			If (d<c.minimum Or c.minimum<0) Or (d>c.maximum Or c.maximum<0)
				If dist=0
					x=1
					y=0
					dist=.0001
				EndIf
				diff=((dist-c.dist)/dist)*c.tension
				x=x*diff
				y=y*diff
				mass1=c.b.mass/(c.a.mass+c.b.mass)
				mass2=c.a.mass/(c.a.mass+c.b.mass)
				c.a.x=c.a.x-mass1*x*c.a.fx
				c.a.y=c.a.y-mass1*y*c.a.fy
				c.b.x=c.b.x+mass2*x*c.b.fx
				c.b.y=c.b.y+mass2*y*c.b.fy
				c.a.xv=c.a.xv-mass1*x*c.a.fx
				c.a.yv=c.a.yv-mass1*y*c.a.fy
				c.b.xv=c.b.xv+mass2*x*c.b.fx
				c.b.yv=c.b.yv+mass2*y*c.b.fy
			EndIf
			DrawLine c.a.x,c.a.y,c.b.x,c.b.y
		Next
	EndFunction
	
	Method After:constraint()
		Local link:TLink = in_group.lyne_list.FindLink(Self).NextLink()
		If link Then Return constraint(link.Value())
		Return Null
	EndMethod
End Type

'Local point0:point,point1:point
'\                    /
' \                  /
'  \                /
'   \              /
'
'      __________
mass=10000
Local point0:point,point1:point,point2:point,point3:point
point0=point.Create(100,100,0,0,.0,.0,0,mass,0,0)
point1=point.Create(300,300,0,0,.0,.0,0,mass,0,0)
point2=point.Create(100,110,0,0,.0,.0,0,mass,0,0)
point3=point.Create(300,310,0,0,.0,.0,0,mass,0,0)
constraint.Create(point0,point1,-1,1,-1,-1,1)
constraint.Create(point0,point2,-1,1,-1,-1,1)
constraint.Create(point2,point3,-1,1,-1,-1,1)
constraint.Create(point3,point1,-1,1,-1,-1,1)

point0=point.Create(700,100,0,0,.0,.0,0,mass,0,0)
point1=point.Create(500,300,0,0,.0,.0,0,mass,0,0)
point2=point.Create(700,110,0,0,.0,.0,0,mass,0,0)
point3=point.Create(500,310,0,0,.0,.0,0,mass,0,0)
constraint.Create(point0,point1,-1,1,-1,-1,1)
constraint.Create(point0,point2,-1,1,-1,-1,1)
constraint.Create(point2,point3,-1,1,-1,-1,1)
constraint.Create(point3,point1,-1,1,-1,-1,1)

point0=point.Create(290,405,0,0,.0,.0,0,mass,0,0)
point1=point.Create(510,405,0,0,.0,.0,0,mass,0,0)
point2=point.Create(290,415,0,0,.0,.0,0,mass,0,0)
point3=point.Create(510,415,0,0,.0,.0,0,mass,0,0)
constraint.Create(point0,point1,-1,1,-1,-1,1)
constraint.Create(point0,point2,-1,1,-1,-1,1)
constraint.Create(point2,point3,-1,1,-1,-1,1)
constraint.Create(point3,point1,-1,1,-1,-1,1)

point0=point.Create(0,450,0,0,.0,.0,0,mass,0,0)
point1=point.Create(150,600,0,0,.0,.0,0,mass,0,0)
constraint.Create(point0,point1,-1,1,-1,-1,1)

point0=point.Create(800,450,0,0,.0,.0,0,mass,0,0)
point1=point.Create(650,600,0,0,.0,.0,0,mass,0,0)
constraint.Create(point0,point1,-1,1,-1,-1,1)

point0=point.Create(200,50,0,0,.99,.99,0,5,0,0)
point1=point.Create(300,50,0,0,.99,.99,0,5,0,0)
point2=point.Create(400,150,0,0,.99,.99,0,5,0,0)
point3=point.Create(300,150,0,0,.99,.99,0,5,0,0)
constraint.Create(point0,point1,100,1,-1,-1,1)
constraint.Create(point1,point2,100,1,-1,-1,1)
constraint.Create(point2,point3,100,1,-1,-1,1)
constraint.Create(point3,point0,100,1,-1,-1,1)
constraint.Create(point0,point2,Sqr(100*100+100*100),1,-1,-1,0)
constraint.Create(point1,point3,Sqr(100*100+100*100),1,-1,-1,0)

point0=point.Create(350,200,0,0,.99,.99,0,5,0,0)
point1=point.Create(450,200,0,0,.99,.99,0,5,0,0)
point2=point.Create(450,300,0,0,.99,.99,0,5,0,0)
point3=point.Create(350,300,0,0,.99,.99,0,5,0,0)
constraint.Create(point0,point1,90,1,-1,-1,1)
constraint.Create(point1,point2,90,1,-1,-1,1)
constraint.Create(point2,point3,90,1,-1,-1,1)
constraint.Create(point3,point0,90,1,-1,-1,1)
constraint.Create(point0,point2,Sqr(90*90+90*90),1,-1,-1,0)
constraint.Create(point1,point3,Sqr(90*90+90*90),1,-1,-1,0)

Global main_loop:Int
Local cx:Int=400,cy:Int=100
While KeyHit(KEY_ESCAPE)=0
Cls
constraint.UpdateConstraints()
SetColor 255,255,255
SetAlpha 1
DrawText "Click to fire",0,0
DrawText "WASD to move turret",0,20
FPS(0,40)
If KeyDown(KEY_W)=1 Then cy=cy-3
If KeyDown(KEY_S)=1 Then cy=cy+3
If KeyDown(KEY_A)=1 Then cx=cx-3
If KeyDown(KEY_D)=1 Then cx=cx+3
If cx<0 Then cx=0
If cx>800 Then cx=800
If cy<0 Then cy=0
If cy>600 Then cy=600
Local angle:Float=ATan2(cy-MouseY(),cx-MouseX())+180
SetAlpha 1
SetColor 255,255,255
DrawLine cx,cy,cx+Cos(angle)*100,cy+Sin(angle)*100
point.UpdatePoints()
If KeyDown(KEY_SPACE)
	For p:point=EachIn point.point_list
		p.xv=p.xv+Rand(-5,5)
		p.yv=p.yv+Rand(-5,5)
	Next
EndIf
If KeyHit(KEY_F10) Then take_screenshot()
main_loop=main_loop+1
If MouseDown(1)=1 And main_loop>5
	main_loop=0
	speed:Int=100
	point.Create(cx,cy,Cos(angle)*speed,Sin(angle)*speed,.99,.99,15,5,0,0)
EndIf
group.Update()
Flip
Wend
EndGraphics()
End

Function oval2(x:Float,y:Float,width:Float,height:Float,fill:Int=1)
glpolygonmode(GL_FRONT,GL_FILL)
If fill=0 Then glpolygonmode(GL_FRONT,GL_LINE)
DrawOval x,y,width,height
glpolygonmode(GL_FRONT,GL_FILL)
EndFunction

Function rect2(x:Float,y:Float,width:Float,height:Float,fill:Int=1)
glpolygonmode(GL_FRONT,GL_FILL)
If fill=0 Then glpolygonmode(GL_FRONT,GL_LINE)
DrawRect x,y,width,height
glpolygonmode(GL_FRONT,GL_FILL)
EndFunction

Function LinesCross:Int(x0:Float,y0:Float,x1:Float,y1:Float,x2:Float,y2:Float,x3:Float,y3:Float)
	Local d:Float=(x1-x0)*(y3-y2)-(y1-y0)*(x3-x2)
	If Abs(d)<0.0001 Then Return -1
	Local n:Float=(y0-y2)*(x3-x2)-(x0-x2)*(y3-y2)
	Local AB:Float=((y0-y2)*(x3-x2)-(x0-x2)*(y3-y2))/d
	If AB>0.0 And AB<1.0
		Local CD:Float=((y0-y2)*(x1-x0)-(x0-x2)*(y1-y0))/d
		If CD>0.0 And CD<1.0 
			linx=x0+AB*(x1-x0)
			liny=y0+AB*(y1-y0)
			Return 1
		EndIf
	EndIf
	Return 0
End Function

Function LineCircle:Int(x0:Float,y0:Float,x1:Float,y1:Float,cx:Float,cy:Float,cr:Float)
	'thanks to daftabrush @gamedev.net for the 's' equation
	Local d:Float=(x0-x1)*(x0-x1)+(y0-y1)*(y0-y1)
	If d=0 Then d=.0001
	Local s:Float=((cx-x0)*(x1-x0)+(cy-y0)*(y1-y0))/d
	If s<0 Then s=0
	If s>1 Then s=1
	x1=x0+(x1-x0)*s
	y1=y0+(y1-y0)*s
	If (cx-x1)*(cx-x1)+(cy-y1)*(cy-y1)<cr*cr
		lcx=x1
		lcy=y1
		Return 1
	EndIf
	Return 0
End Function

Function ClosestPoint(x0:Float,y0:Float,x1:Float,y1:Float,cx:Float,cy:Float,cap:Int)
	Local d:Float=(x0-x1)*(x0-x1)+(y0-y1)*(y0-y1)
	If d=0 Then d=.0001
	Local s:Float=((cx-x0)*(x1-x0)+(cy-y0)*(y1-y0))/d
	If cap=1
		If s<0 Then s=0
		If s>1 Then s=1
	EndIf
	cpx=x0+(x1-x0)*s
	cpy=y0+(y1-y0)*s
EndFunction

Function AngleDifference:Float(x0:Float,y0:Float,x1:Float,y1:Float,x2:Float,y2:Float,x3:Float,y3:Float)
Local angle0:Float,angle1:Float
If x0>x1
	angle0=ATan2(y0-y1,x0-x1)+180
Else
	angle0=ATan2(y1-y0,x1-x0)+180
EndIf
If x2>x3
	angle1=ATan2(y2-y3,x2-x3)+180
Else
	angle1=ATan2(y3-y2,x3-x2)+180
EndIf
Return 1.0-Abs(Abs(angle0-angle1)-90)/90.0
End Function

Function RectOverlap(x:Int,y:Int,w:Int,h:Int,xx:Int,yy:Int,ww:Int,hh:Int)
If x+w>xx And y+h>yy And xx+ww>x And yy+hh>y Then Return 1
Return 0
End Function

Function FPS(x:Int,y:Int)
If MilliSecs()-fps_time>1000
	fps_fps=fps_loop/(MilliSecs()-fps_time)
	fps_time=MilliSecs()
	fps_loop=0
EndIf
fps_loop=fps_loop+1
SetColor 255,255,255
SetAlpha 1
DrawText "FPS: "+(Int(fps_fps*1000.0)),x,y
EndFunction

Function take_screenshot()
	Local filename:String, padded:String
	Local num:Int = 0
	padded = num
	While padded.length < 3 
		padded = "0"+padded
	Wend
	filename = "screen"+padded+".png"
	While FileType(filename) <> 0
		num:+1
		padded = num
		While padded.length < 3 
			padded = "0"+padded
		Wend
		filename = "screen"+padded+".png"
	Wend
	Local img:tpixmap = GrabPixmap(0,0,GraphicsWidth(),GraphicsHeight())
	SavePixmapPNG(img,filename)
EndFunction


Here's an overview of how the system is structured:
there's points and constraints. Points can have masses, radius's, velocities, etc. Constraints can connect 2 points and potentialy become lines. The circles in the demo are points with radius's, the lines are constraints flagged to be lines.
When a line or circle gets created, it gets added to a list in a group. To begin with the only group is world_group and if a circle or line isn't assigned a group, thats where it goes. Groups can have self collisions enabled/disabled. Each group also has a bouding box to determine if it's colliding with another group.
A line is 2 connected points. If the masses of the points differ, then the mass of a point on the line is determined by how far/close the point is to the end points. Lines can also have circles on the each end by raising the radius of the end points in the demo.

tonyg, the reason the balls won't move out from the corners is because the corner isn't a polygon in the sense you are thinking of it. It is just a line...if the ball hits the line it responds, it isn't a filled corner. This is also why balls can stay inside the boxes.

The reason why the balls get in them boxes or out of the corners is because other objects force them to move to a point that is at least half way on the other side of a line, so when the ball and line collide it forces it the rest of the way to the other side.

Haram, i've heard about the SAT but my understanding of it still has some holes:
1) get the angle between the 2 bodies
2) draw a line in between them perpendicular to the one connecting them
3) if a point from both bodies crosses the line then they are colliding.

If this is correct then it seems like a bad idea waiting to happen...

The lines do abort detection if they are parallel (see the LinesCross function).

Yes SAT it's to complicated to get used to it ( I haven't implimented any it's still confusing for me too )
The method you are saying may work but it's not the best way to do it. I tried sometime before with no success. But the overall idea is to make all the checks in 1D. A good place to start is : http://gpwiki.org/index.php/Polygon_Collision
Also make a search for the polycollly. It's maybe safe to say to you not to stuck with this method.

If I am not wrong you are using Verlet integretion.
Make a try of Flade's traslation in BMax by Dooz you can find it near the end of : MaxPhisics Comunity project thread. Click it in my sig to go there.

Last grap a vector lib or start to create one. I am sure coding will be easier and you will find out that you were repeating your self. This is what I am doing. I am using a Vector lib for expirimenting and when I have the disired output I break down the equations to get as minnimum equations I can get.

I am not the best person to help but I hope I helped.

May someone tell me how i can change friction and gravity on flounder22001's example, pls?

Edit:
Ok, i found the gravity, but not the friction :(