Simulating a hanging chain

Blitz3D Forums/Blitz3D Programming/Simulating a hanging chain

PoliteProgrammer(Posted 2007) [#1]
Okay, I'm trying to simulate a chain hanging under the influence of gravity. The chain is made up of discrete links. As in a real chain, the links cannot stretch, so each link can vary from the next in rotation only.

I've tried a few different methods to get this working (only in 2d at the moment) but nothing's really worked. Does anyone have a suggested algorithm to get this working?


IPete2(Posted 2007) [#2]
James,

There is a Flash book called Actionscript Animation - Making Things Move! by Keith Peters.

You'll have to translate to Blitz, from something like this book, or you could invest some time in Vipr's ODE for B3d or BMax, which ever language you are using.

EasyTok also allow you to build this sort of thing in B3d too. Otherwise I think there may be some code in the archive to do with such things.

IPete2.


Stevie G(Posted 2007) [#3]
No need for fancy 3rd party physics engines for this kind of thing.

Here's an old thrust demo by Wiebo which uses verlet integration ..




IPete2(Posted 2007) [#4]
I wish I understood Verlets Stevie! I think it would be so useful for all sorts of things.

IPete2.


Stevie G(Posted 2007) [#5]

I think it would be so useful for all sorts of things.



It definately is very useful but can consume many months of your life due to some of it's limitations.

I found this page a while back which has loads of links and examples ... you should have a butchers.

http://movil.be/index.php?s=delicious.p&tag=verlet


PoliteProgrammer(Posted 2007) [#6]
Thank you Stevie G, that was exactly what I was looking for; I'll learn how that works and modify it to my needs. Thanks!


PoliteProgrammer(Posted 2007) [#7]
Hi, I've been trying out the code, and i'm fairly confident on how it's working, but could anyone explain this line:


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


What physical quantity does diff# represent?

I've also attempted to modify the code quite significantly (you'll notice my use of arrays, because I'll need them for something else I want to do). It's not working, would anyone mind pointing out anything they see that's wrong with it?


Graphics 640, 480, 16, 0
SetBuffer BackBuffer()
SeedRnd MilliSecs()
TFormFilter False
frameTimer = CreateTimer(60)

timeStep# = 0.016666
g# = 9.81
drag# = 0.995
numLinks = 100
massOfEachLink = 60
restLength# = 20


Type playerType
Field x#, y#, vX#, vY#, aX#, aY#
Field mass#
End Type

player.playerType = New playerType
player\x = 100
player\y = 250
player\mass = 1


Type clawType
Field x#, y#, aX#, aY#
End Type


Type chainLinkType
Field x#, y#, oldX#, oldY#, aX#, aY#, mass#
End Type

Dim chainArray.chainLinkType(numLinks - 1)
For i = 0 To numLinks - 1

  chainArray(i) = New chainLinkType
  chainArray(i)\x = 50 + i * 540 / (numLinks - 1)
  chainArray(i)\y = 50
  chainArray(i)\oldX = chainArray(i)\x
  chainArray(i)\oldY = chainArray(i)\y
  chainArray(i)\mass = massOfEachLink

Next




While Not KeyHit(1)
WaitTimer frameTimer
Cls


  ; Controls



  For i = 0 To numLinks - 1
    ; Apply gravity to particles
    chainArray(i)\aY = chainArray(i)\aY + g / chainArray(i)\mass

    ; Verlet Integration
    tempX# = chainArray(i)\x
    tempY# = chainArray(i)\y

    chainArray(i)\x = chainArray(i)\x * (1 + drag) - drag * chainArray(i)\oldX + chainArray(i)\aX * timeStep * timeStep
    chainArray(i)\y = chainArray(i)\y * (1 + drag) - drag * chainArray(i)\oldY + chainArray(i)\aY * timeStep * timeStep
    chainArray(i)\oldX = tempX
    chainArray(i)\oldY = tempY

    ; Reset acceleration after moving particle
    chainArray(i)\aX = 0 : chainArray(i)\aY = 0
  Next



  ; Make each link experience a force from the surrounding ones
  For i = 0 To numLinks - 2

    temp_dx# = chainArray(i + 1)\x - chainArray(i)\x
    temp_dy# = chainArray(i + 1)\y - chainArray(i)\y
    temp_Separation# = Sqr(temp_dx * temp_dx + temp_dy * temp_dy)
    temp_Extension# = temp_Separation - restLength

    ; Start 
    temp_SpringForce# = temp_Extension / ( temp_Separation * (chainArray(i)\mass + chainArray(i + 1)\mass) )
    chainArray(i)\x = chainArray(i)\x + chainArray(i)\mass * temp_dx * temp_SpringForce
    chainArray(i)\y = chainArray(i)\y + chainArray(i)\mass * temp_dy * temp_SpringForce
    chainArray(i + 1)\x = chainArray(i + 1)\x - chainArray(i + 1)\mass * temp_dx * temp_SpringForce
    chainArray(i + 1)\y = chainArray(i + 1)\y - chainArray(i + 1)\mass * temp_dy * temp_SpringForce



  Next



  chainArray(0)\x = 50
  chainArray(0)\y = 50
  chainArray(numLinks - 1)\x = 590
  chainArray(numLinks - 1)\y = 50





  ; Draw Links
  For i = 0 To numLinks - 1
    Rect chainArray(i)\x, chainArray(i)\y, 1, 1, 1
  Next



Flip
Wend
End




[Edit] Oops, forgot that I was the one that posted last.


Yo! Wazzup?(Posted 2007) [#8]
I'd try taking out the code and seeing what happens...
That's one of the fun parts of Blitz.


Stevie G(Posted 2007) [#9]
The diff is a distance measurement which tells you how far from it's restlength a link is. It uses this to adjust both points proportionate to their inversemass so that a heavier particle isn't moved as far as a lighter one but they still maintain their distance appart.

Really the 'Mass' field should be 'InverseMass'. Note if you set this to 0 the particle is immovable automatically.

I've changed a couple of things. Your initial particle positions were causing major energy in the system so I fixed this. I also made the inversemasses lower so that gravity has a bigger effect. It seems to work ..



p.s. Use the TAB button to indent your code .. not spaces!!

Stevie


PoliteProgrammer(Posted 2007) [#10]
Thanks, that was brilliant - just what I'm looking for. Thanks for explaining some bits too. I'm confident that I know how this is working now, so I should be able to apply it to other things. :)


bytecode77(Posted 2007) [#11]

www.devil-engines.net :P