Realistic 'rope' physics?

Blitz3D Forums/Blitz3D Programming/Realistic 'rope' physics?

AdsAdamJ(Posted 2005) [#1]
Hi, I was messing around the other night practicing my maths work, etc., and I came up with this almost by accident:

Graphics 640, 400, 32, 1

SetBuffer BackBuffer()


Type dat
	Field x#, y#
	Field h#, v#
End Type
Global ball.dat

; Create 100 links in the chain
For n=0 To 99
	ball.dat = New dat
	ball\x = Rand(GraphicsWidth())
	ball\y = Rand(GraphicsHeight())
Next



Repeat
	Cls

	; Draw blue oval for the mouse
	Color 0, 0, 255
	Oval MouseX()-5, MouseY()-5, 10, 10

	; set coords for first link in chain to current mouse coords
	lastx# = MouseX()
	lasty# = MouseY()
	lastv# = MouseYspeed()
	lasth# = MouseXspeed()
	
	
	For ball.dat = Each dat
		ball\v = ball\v + .5							; Increase Y velocity by 1 to simulate gravity
			
;		ball\h = ball\h + (lastx - ball\x) * .05	; Calcuate current velocity by comparing current link to previous links positions
;		ball\v = ball\v + (lasty - ball\y) * .05
		
		ball\v = (ball\v + lastv) * .5				; Average the velocities between the current link and the previous link
		ball\h = (ball\h + lasth) * .5
		
		ball\v = ball\v * .95						; Apply friction from air resistance
		ball\h = ball\h * .95
		ball\x = ball\x + ball\h					; Move link in the new direction
		ball\y = ball\y + ball\v
		
		; Stop chain link from dropping below screen or off to the sides
		If ball\y > GraphicsHeight() - 10 Then ball\y = GraphicsHeight() - 10: ball\v = -ball\v
		If ball\x < 0 Then ball\x = 0: ball\h = - ball\h
		If ball\x > GraphicsWidth() Then ball\x = GraphicsWidth(): ball\h = -ball\h

		; Calculate the distance between current & previous links
		xdiff# = lastx - ball\x
		ydiff# = lasty - ball\y
		dist# = Sqr(xdiff * xdiff + ydiff * ydiff)
		
		; Calculate the vector normal of where the link should be
		If Abs(dist#) > 0 Then
			xd# = (lastx - ball\x) / dist#
			yd# = (lasty - ball\y) / dist#
		Else
			xd# = 0
			yd# = 0
		End If
		
		; Set the distance between current link and previous link
		xd = xd * 5
		yd = yd * 5

		; Calculate new position
		ball\x = (lastx - xd)
		ball\y = (lasty - yd)
		
		; Draw the link
		Color 255, 0, 0
		Oval ball\x-2, ball\y-2, 4, 4
		Line lastx, lasty, ball\x, ball\y

		; Save current links coords and velocities
		lastx# = ball\x
		lasty# = ball\y
		lasth# = ball\h
		lastv# = ball\v
	Next


	
	Flip
Until KeyHit(1)

End


Now, I have *no idea* if this is the 'proper' way of simulating this sort of thing, I just worked it out as best I could. I can't help feeling that I can improve on this though. Is there anybody who might be able to give me any pointers as to how I might improve on this?

the biggest problem I have at the moment is that the links 'concertina' up when the gravity is set below a certain amount. I don't want that to happen basically, I just want the rope to move a little more realistically.

EDIT: Just edited out a couple of lines and altered a couple.

EDIT 2: Ha! That's seems to have done the trick. Well, sort of.


ryan scott(Posted 2005) [#2]
hey that is fun. nice work!


Stevie G(Posted 2005) [#3]
The proper way would be to use verlet integration where the velocity is implicit. Much more stable than Euler. You could look up Jakobsens paper on Gamasutra. Here's an old example by Weibo .....


; quick thrust game, by Wiebo de Wit
; Using verlet integration for movement and stick constraints for the ball and chain =]
; green line is your ship. I'm sorry but i didn't have the strength to include my new
; vector object engine. a and s to rotate, r-shift to thrust

Const TIMESTEP# = 0.05
Const GRAVITYANGLE = 0			; 0 = straight down, 90 = right, etc
Const GRAVITYFORCE# = 10
Const DRAG# = 0.995
Const THRUST# = 40
Const NUM_PARTICLES = 5
Const RESTLENGTH# = 20

Type Particle
	Field x#, y#
	Field old_x#, old_y#
	Field a_x#, a_y#
	Field mass#
	Field nxt.particle
End Type

Type Player
	Field angle#
	Field thrust#
	Field point.particle
End Type

Global player.player, p.particle

Graphics 640,480
SetBuffer BackBuffer()

; create player
player.player = New player

; player is a particle too, but you can control it
player\point = New particle
p.particle = player\point
p\x = 200 : p\y = 200
p\old_x = 200 : p\old_y = 200
p\a_x = 0 : p\a_y = 0

; make ship heavy
p\mass =1

For count = 1 To NUM_PARTICLES

	p\nxt = New particle
	p = p\nxt

	p\x = 200 : p\y = 200
	p\old_x = Rand(200,205) 
	p\old_y = Rand(200,205)
	p\a_x = 0 : p\a_y = 0
	p\mass = 60
Next

; last particle is ball. make heavy
p\mass = 1

; loop
While KeyHit( 1 ) = False

	GetInput()
	ApplyPhysics()
	Verlet()
	ConstrainParticlesMass()
	DrawParticles()
	Flip
	Cls

Wend

; ------------------------------------------------------------

Function GetInput()

	If KeyDown( 203 )
		;rotate
		player\angle = player\angle + 5
	EndIf

	If KeyDown( 205 )
		;rotate
		player\angle = player\angle - 5
	EndIf

	If KeyDown( 200 )
		;thrust, adjust player particle acceleration
		p.particle = player\point
		p\a_x = p\a_x - Sin( player\angle ) * THRUST
		p\a_y = p\a_y - Cos( player\angle ) * THRUST
	EndIf

End Function


Function ApplyPhysics()

	; apply gravity to particles
	For p.particle = Each particle
		p\a_x = p\a_x + Sin( GRAVITYANGLE ) * GRAVITYFORCE / p\mass
		p\a_y = p\a_y + Cos( GRAVITYANGLE ) * GRAVITYFORCE / p\mass
	Next

End Function


Function ConstrainParticlesMass()

	p.particle = player\point

	While p\nxt <> Null
		dx# = p\nxt\x - p\x
		dy# = p\nxt\y - p\y

		deltalength# = Sqr( dx*dx + dy*dy )
		diff# = ( deltalength - RESTLENGTH ) / (deltalength * ( -p\mass + -p\nxt\mass ) )

		p\x = p\x + -p\mass * dx * diff
		p\y = p\y + -p\mass * dy * diff
		p = p\nxt
		p\x = p\x - -p\mass * dx * diff
		p\y = p\y - -p\mass * dy * diff
	Wend

End Function


Function DrawParticles()

	p.particle = player\point

	; draw player, green line

	Color 0,255,0
	dx# = Sin( player\angle) 
	dy# = Cos( player\angle)
	Line p\x-dx*20, p\y-dy*20 , p\x + dy*5, p\y - dx*5
	Line p\x-dx*20, p\y-dy*20 , p\x - dy*5, p\y + dx*5
	Line p\x + dy*5, p\y - dx*5, p\x - dy*5, p\y + dx*5

	; draw line
	Color 255,0,0
	While p\nxt <> Null
		Line p\x, p\y, p\nxt\x, p\nxt\y
		p = p\nxt
	Wend

	; draw ball at end
	Color 255,255,0
	Oval p\x -14, p\y-14, 28,28, 0

	; white dots, for clarity
	Color 255,255,255
	For p.particle =Each particle
		Plot p\x, p\y
	Next

End Function


Function Verlet()

	; eg: move particles, introducing drag

	For p.particle = Each particle

		x# = p\x
		y# = p\y

		tempx# = p\x
		tempy# = p\y

		oldx# = p\old_x
		oldy# = p\old_y

		p\x = p\x + DRAG * x - DRAG * oldx + p\a_x * TIMESTEP * TIMESTEP
		p\y = p\y + DRAG * y - DRAG * oldy + p\a_y * TIMESTEP * TIMESTEP

		p\old_x = tempx
		p\old_y = tempy

		; reset acceleration after moving particle
		p\a_x = 0 : p\a_y = 0
	Next

End Function



AdsAdamJ(Posted 2005) [#4]
Thanks for that, I'm going to have a closer look at this today and try to understand it. Great stuff!


poopla(Posted 2005) [#5]
Essentially it uses change in location as an integral towards velocity. This change in location comes from a spring limiter between "particles" in the solution. Basically, you sum all forces(including the spring force from any particles the particle in question is linked to). After suming the forces on this particle, you integrate them into its acceleration. I'm not going to go into it any more as there are some great papers on the subject with formulas. All in all, when the different principles of the integration scheme are working together, it creates a simulation applicable for rope, non deforming objects, and cloth.(other things as well but these are the common uses.)


AdsAdamJ(Posted 2005) [#6]
I'm just going through the Gamasutra article Stevie G suggested. I'm beginning to see how the system works, it's quite versatile. Ironically I began to write something similar to that in the program above, but ultimately used the Euler system instead. I'll rewrite this little program and post a new version of it when I've got to grips with Verlets more.

Thanks for both your help!


John Blackledge(Posted 2005) [#7]
@Dev : Ah, so that's how they did swirling dresses in Shrek.
Which software do the pros us to create films like that?


VP(Posted 2005) [#8]
John: Maya (probably).


poopla(Posted 2005) [#9]
And they probably use something alot more advanced :).