physics not working "right"

Blitz3D Forums/Blitz3D Programming/physics not working "right"

flounder22001(Posted 2005) [#1]
i put together this line-to-line physics demo. Part of the collision handling was taken from a circle colision demo, which is where my problem is.

When 2 circles collide, you only need to find 1 angle between them to handle the collision, when 2 lines collide you need 2 angles to handle collsion. I've tried to modify the code to use 2 angles but every time just makes it worse.

The documentation at the beginning was for me to remind myself exactly how to handle everything, so you can ignore it. The collision that i need help on are in the UpdateLynes() function.

Just use the arrow keys to make one of the lines move.

;find the % of each mass it will take based off the distance from each point
;	a=line dist
;	b=dist from point 1
;	mass1=mass of first point
;	mass2=mass of second point
;	p1=percent for point 1
;	p2=percent for point 2
;	p2=b/a
;	p1=1.0-p2

;find out the mass of the point of contact
;	tmass=total mass for PoC
;	tmass=p1*mass1+p2*mass2

;find the velocities of the PoC
;	tvelx=total x velocity for the PoC
;	tvely=total y velocity for the PoC
;	p1xv/yv=x/y velocity of point 1
;	p2xv/yv=x/y velocity of point 2
;	tvelx=p1*p1xv+p2*p2xv
;	tvely=p1*p1yv+p2*p2yv

;find the same for the other point
;	tmass1=mass for other line's PoC
;	tvelx1=x velocity for other line's PoC
;	tvely1=y velocity for other line's PoC

;perfrom circle collision with the calculated values

;based on the offset of the x/y's and percent's, affect the points accordingly
;	sx=amount tvelx shifted
;	sy=amount tvely shifted
;	p1xv=p1xv+sx*p1
;	p1yv=p1yv+sy*p1
;	p2xv=p2xv+sx*p2
;	p2yv=p2yv+sy*p2

Graphics 800,600,16,2

Global linx#,liny#

Type point
	Field x#,y#
	Field xv#,yv#
	Field fx#,fy#
	Field mass#
End Type

Type lyne
	Field a.point
	Field b.point
	Field dist#
	Field tension#
	Field cur_d#
End Type

a.point=CreatePoint(100,100,.99,.99,0,0,1)
b.point=CreatePoint(200,100,.99,.99,0,0,10)
CreateLyne(a,b,100,1)
For i=0 To 20
CreateLyne(CreatePoint(300+i*5,100,.99,.99,0,0,1),CreatePoint(300+i*5,200,.99,.99,0,0,1),100,1)
Next
SetBuffer BackBuffer()
While KeyHit(1)=0
Cls
	If KeyDown(200)=1
		;a\yv=a\yv-.1
		b\yv=b\yv-.1
	EndIf
	If KeyDown(208)=1
		;a\yv=a\yv+.1
		b\yv=b\yv+.1
	EndIf
	If KeyDown(203)=1
		;a\xv=a\xv-.1
		b\xv=b\xv-.1
	EndIf
	If KeyDown(205)=1
		;a\xv=a\xv+.1
		b\xv=b\xv+.1
	EndIf
	UpdatePoints(1)
	UpdateLynes()
Flip
Wend

Function CreatePoint.point(x#,y#,fx#,fy#,xv#,yv#,mass#)
p.point=New point
p\x=x
p\y=y
p\xv=xv
p\yv=yv
p\fx=fx
p\fy=fy
p\mass=mass
Return p
End Function

Function CreateLyne.lyne(a.point,b.point,dist#,tension#)
l.lyne=New lyne
l\a=a
l\b=b
l\dist=Sqr((a\x-b\x)*(a\x-b\x)+(a\y-b\y)*(a\y-b\y))
If dist>0 Then l\dist=dist
l\cur_d=l\dist
l\tension=tension
Return l
End Function

Function UpdatePoints(boundries=0)
For p.point=Each point
p\xv=p\xv*p\fx
p\yv=p\yv*p\fy
p\x=p\x+p\xv
p\y=p\y+p\yv
If boundries=1
	If p\x<0
		p\x=0
		p\xv=-p\xv
	EndIf
	If p\x>800
		p\x=800
		p\xv=-p\xv
	EndIf
	If p\y<0
		p\y=0
		p\yv=-p\yv
	EndIf
	If p\y>600
		p\y=600
		p\yv=-p\yv
	EndIf
EndIf
Next
End Function

Function UpdateLynes()
For l.lyne=Each lyne
d#=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))
If d=0 Then d=.0001
diff#=((d-l\dist)/d)*l\tension
x#=(l\a\x-l\b\x)
y#=(l\a\y-l\b\y)
mass1#=l\a\mass/(l\a\mass+l\b\mass)
mass2#=l\b\mass/(l\a\mass+l\b\mass)
x0#=-x*mass2*l\a\fx*diff
l\a\x=l\a\x+x0
l\a\xv=l\a\xv+x0
y0#=-y*mass2*l\a\fy*diff
l\a\y=l\a\y+y0
l\a\yv=l\a\yv+y0
x1#=x*mass1*l\b\fx*diff
l\b\x=l\b\x+x1
l\b\xv=l\b\xv+x1
y1#=y*mass1*l\b\fy*diff
l\b\y=l\b\y+y1
l\b\yv=l\b\yv+y1
l\cur_d=d-diff
Line l\a\x,l\a\y,l\b\x,l\b\y
Next
For l.lyne=Each lyne
ll.lyne=l
While ll<>Last lyne
ll=After ll
;For ll.lyne=Each lyne
	;check to see if the lines are colliding
	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
		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
		p2#=d1/l\cur_d
		If p2>1.0 Then p2=1.0
		p1#=1.0-p2
		p4#=d2/ll\cur_d
		If p4>1.0 Then p4=1.0
		p3#=1.0-p4
		tmass1#=p1*l\a\mass+p2*l\b\mass
		tmass2#=p3*ll\a\mass+p4*ll\b\mass
		tvelx1#=p1*l\a\xv+p2*l\b\xv
		tvely1#=p1*l\a\yv+p2*l\b\yv
		tvelx2#=p3*ll\a\xv+p4*ll\b\xv
		tvely2#=p3*ll\a\yv+p4*ll\b\yv
		angle#=ATan2((l\a\y+l\b\y)/2.0-(ll\a\y+ll\b\y)/2.0,(l\a\x+l\b\x)/2.0-(ll\a\x+ll\b\x)/2.0)+180
		;find the how much is crossing over the other line
		If d1>l\cur_d/2.0 Then d1=l\cur_d-d1
		If d2>ll\cur_d/2.0 Then d2=ll\cur_d-d2
		x#=Cos(angle)
		y#=Sin(angle)
		mass1#=tmass2/(tmass1+tmass2)
		mass2#=tmass1/(tmass1+tmass2)
		offset#=Sqr(d1+d2)
		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
		;-------------------------
		q1# = min(p1, p2)
		q2# = min(p3, p4)
		qt# = q1 + q2
		a1# = ATan2(l\b\y-l\a\y, l\b\x-l\a\x)
		If l\b\x-l\a\x < 0 Then a1 = a1 + 180
		a2# = ATan2(ll\b\y-ll\a\y, ll\b\x-ll\a\x)
		If ll\b\x-ll\a\x < 0 Then a2 = a2 + 180
		angle# = (a1*q1 + a2*q2) / qt - 90
		x#=Cos(angle)
		y#=Sin(angle)
		;-------------------------
		v1#=tvelx1*x+tvely1*y
		v2#=tvelx2*x+tvely2*y
		p#=(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
	EndIf
;Next
Wend
Next
End Function

Function min#(x#,y#)
If x<y Then Return x
Return y
End Function

Function LinesCross(x0#,y0#,x1#,y1#,x2#,y2#,x3#,y3#)
	n#=(y0-y2)*(x3-x2)-(x0-x2)*(y3-y2)
	d#=(x1-x0)*(y3-y2)-(y1-y0)*(x3-x2)
	If (Abs(d)<0.0001) Then Return 0
	Sn#=(y0-y2)*(x1-x0)-(x0-x2)*(y1-y0)
	AB#=n/d
    If AB>0.0 And AB<1.0
        CD#=Sn/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  

(btw, this is 2d)


VP(Posted 2005) [#2]
Now, I'm a bit dim where it comes to physics modelling, but running your program makes me think that you've got the math right. Everything works as expected except that it seems when your lines collide, they sometimes continue to touch, causing them to 'slide' along each other.


octothorpe(Posted 2005) [#3]
Fixed indentation, made the "player line" red, haven't touched the math:




octothorpe(Posted 2005) [#4]
I don't think you need two collision angles.

Imagine an ideal simulation where you're able to detect when two lines start touching, as opposed to having already moved them to be intersecting. Either the lines will strike perfectly parallel to each other (let's ignore this case for now) or one line's point will strike the other line. The latter line's slope should be your collision normal (angle.)

Since you're not running an ideal simulation, perhaps you could take the average of both lines' slopes, weighing heavily in favour of the line which has the point of intersection furthest from both its points. e.g.

				q1# = min(p1, p2)
				q2# = min(p3, p4)
				qt# = q1 + q2
				a1# = atan2(l\b\y-l\a\y, l\b\x-l\a\x)
				if l\b\x-l\a\x < 0 then a1 = a1 + 180
				a2# = atan2(ll\b\y-ll\a\y, ll\b\x-ll\a\x)
				if ll\b\x-ll\a\x < 0 then a2 = a2 + 180
				angle# = (a1*q1 + a2*q2) / qt - 90


P.S. vinylpusher: it's really difficult to compose a message while you're making faces at me.


octothorpe(Posted 2005) [#5]



flounder22001(Posted 2005) [#6]
fixed *a* problem: mass1 and 2 were switched, however there still the problem of them sliding

i don't have time right now to check out what u wrote octothorpe, but ill try sometime later.


flounder22001(Posted 2005) [#7]
ok, i tried replacing the original angle variable witht he method octothorpe posted. the collision was better but sometimes it would let lines the were close to being perpendicular, slide through eachother.

i knew that when it came to pushign the lines away, the original angle finder worked great, but it didnt work well for transfering velocites, so after the part that pushes the lines away i used octothorpe's angle. So far it works a lot better than before and im pretty satisfied with it :)

there still has to be problems though (im pretty sure i saw a few), so if anyone thinks of something more to fix it will be appreciated.

thanks for the help