simple 2d verlet

Blitz3D Forums/Blitz3D Programming/simple 2d verlet

DarkEagle(Posted 2003) [#1]
hopefully this isnt too much to ask, and ive seen all that great 3d verlet stuff from you lot... so i was hoping that you might be able to implement collisions in this for me? i really dont have a clue where to start. its taken from the article on gamasutra, and it seems to work ok...

thanks

Graphics 800,600,0,2
SetBuffer BackBuffer()

Const TIMESTEP# = 0.05
Const ITERATIONS = 5

Type particle
	Field x#,y#
	Field oldx#,oldy#
	Field xvel#,yvel#
	Field xacc#,yacc#
	Field mass#
End Type

Type link
	Field p0.particle
	Field p1.particle
	Field length#
End Type

a.particle = particle(400-100,300-50)
b.particle = particle(400-50,300+50)
c.particle = particle(400+50,300+50)
d.particle = particle(400+50,300-50)
link a,b,100
link b,c,100
link c,d,100
link d,a,100
link a,c,Sqr(100^2 + 100^2)
link b,d,Sqr(100^2 + 100^2)

While Not KeyHit(1)
Cls

Verlet
SatisfyConstraints
RenderParticles
RenderLinks
ApplyGlobalAcc 0,10

If MouseDown(1)
	a\x = MouseX()
	a\y = MouseY()
End If

Flip
Wend
End


Function Particle.particle(x#,y#,mass#=0.1)

p.particle = New particle
p\x = x
p\y = y
p\oldx = p\x
p\oldy = p\y
p\mass = mass

Return p

End Function


Function Link.link(p0.particle,p1.particle,Length#=10)

l.link = New link
l\p0 = p0
l\p1 = p1
l\length = length

Return l

End Function


Function ApplyGlobalAcc(x#,y#)

For p.particle = Each particle
	p\xacc = x
	p\yacc = y
Next

End Function


Function Verlet()
	For p.particle = Each particle
		tmpX# = p\x#
		tmpY# = p\y#

		p\x# = tmpX# + tmpX# - p\oldx# + p\xacc# * TIMESTEP# * TIMESTEP#
		p\y# = tmpY# + tmpY# - p\oldy# + p\yacc# * TIMESTEP# * TIMESTEP#

		p\oldx# = tmpX#
		p\oldy# = tmpY#
	Next
End Function


Function SatisfyConstraints()

	For j = 1 To ITERATIONS
		For p.particle = Each particle
			If p\x < 50 Then p\x = 50
			If p\y < 50 Then p\y = 50
			If p\x > 750 Then p\x = 750
			If p\y > 550 Then p\y = 550
		Next

		For l.link = Each link
			delX# = l\p1\x - l\p0\x
			delY# = l\p1\y - l\p0\y
			deltalength# = Sqr(delX * delX + delY * delY)
			diff# = (deltalength# - l\length#) / (deltalength# * (-l\p0\mass# + -l\p1\mass#))

			l\p0\x# = l\p0\x# + delX# * -l\p0\mass# * diff#
			l\p0\y# = l\p0\y# + delY# * -l\p0\mass# * diff#

			l\p1\x# = l\p1\x# - delX# * -l\p1\mass# * diff#
			l\p1\y# = l\p1\y# - delY# * -l\p1\mass# * diff#
		Next
	Next
End Function


Function RenderParticles()

For p.particle = Each particle
	Oval p\x-4,p\y-4,8,8
Next

End Function


Function RenderLinks()

For l.link = Each link
	Line l\p0\x,l\p0\y,l\p1\x,l\p1\y
Next

End Function



Bot Builder(Posted 2003) [#2]
What kind of collisions are you looking for? line collisions are easy enough. circle collisions are REALLY easy.

Also, as most of the time your gonna link to particles with a constraint with the restlength of the particles current distance, you might want to simplify the link function.

As for 2d collisions, you'd probably want to talk to bouncer although he will tell you to use the 3d collisions. Which are in fact, faster even when your doing 2d, but You might want it strictly 2d anyway.


Bouncer(Posted 2003) [#3]
Btw. I have not used 3D collisions... Wouldn't touch so slow stuff... I use VERY optimized OBBtrees and customized Sweep and prune algo thru x-axis. Soon to be even faster as I'm currently writing the collision code in asm / c++.

If you are making 3D stuff... then it's the easiest and fastest to use blitzes stuff ... unless you want something faster, but then it's going to be pretty advanced at least in poly to poly level. But if you only want sphere to sphere precision eg. no object to scenery collisions, you can easily write your own optimized sphere to sphere routines which are fater than blitzes.


If your doing 2D ... use circles as collision primitives. They're fast to calculate and pretty universal shapes. They are even used in very accurate collision modelling. Just have to use lot's of 'em :)


Bouncer(Posted 2003) [#4]
Just re-read your topic... so you want 2d. Ok... basic circle to circle collisions:


Every particle has to have radius then:

// so then you basicly test (in pseudo):

dx = particle1_x - particle2_x
dy = particle1_y - particle2_y
particle distance = sqr(dx*dx + dy*dy)
normdist = particleradius1 + particleradius2

if particle distance < normdist then collision occurs

// It's that simple
// Then just move the particles so they are not
// interpenetrating.
// this also calculates the weights... so lighter particle will move more


coldepth = (particle_distance - normdist) / particle_distance

totalweight = p1weight + p2weight

forcex = (dx*coldepth) / totalweight
forcey = (dy*coldepth) / totalweight


particle1x - (forcex * p2weight)
particle1y - (forcey * p2weight)

particle2x + (forcex * p1weight)
particle2y + (forcey * p1weight)


DarkEagle(Posted 2003) [#5]
yay thanks bouncer, that works when the particles collide, but how about when a particle passes through a link? that shouldnt be allowed either, and if im thinking straight, then all i need is circle-line and circle-circle collisions (with reactions) and it should be solid?


Bot Builder(Posted 2003) [#6]
ahh. I was under the impresion that you used 3d cols cause there faster. I guess not. probably someone else. the circle- line thing is the bain of the current systems. It shouldn't be to hard in 2d, but It's pretty dang hard to get fast stuff in 3d. oh well. I don't have any code, but I'm guessing that the best way to do it is find the nearest point on a line(algorithm of some sort). Then find the distance from the sphere to the point. if the radius is greater than the distance then you need to correct for it the same way as you did the circles.

The problem with this is that the line doesn't move. this can be solved, but it takes some maths I don't know yet. The Verlet article on Gamasutra("Advanced charachter physics") covers the problem of point-line.