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).