## Ragdoll Physics

Member
Posts: 338
Joined: 2004.07
Post: #16
Another point- when you update your position, you add the velocity, when you should be adding the velocity * timeElapsed.

Justin Ficarrotta
http://www.justinfic.com
"It is better to be The Man than to work for The Man." - Alexander Seropian
Sage
Posts: 1,066
Joined: 2004.07
Post: #17
The link that Justin left me (about Verlet integration), that isn't the same thing that Najdorf was describing, was it? It doesn't seem that way. Considering all ups and downs, should I go with the position/velocity approach or position/lastposition approach? I don't want to rewrite all my code (even if it only sort of works) if it is a decent way to go.
Member
Posts: 749
Joined: 2003.01
Post: #18
Ok, that's good, only 1 problem, you write

shift[i].x += (circlePos[i+1].x - circlePos[i].x) / 4;

this tries to squeeze them all in 1 point!

I was wrong, you actually have to find the distance between the balls after all: the right code for the shifts is:

for(i = 1; i < NUM_CIRCLES - 1; i++)
{
distance=sqrt( (circlePos[i+1].x - circlePos[i].x)^2+(circlePos[i+1].y - circlePos[i].y)^2+(circlePos[i+1].z - circlePos[i].z)^2)

shift[i].x += (distance-2*radius) / 4*((circlePos[i+1].x - circlePos[i].x)/distance);
shift[i].y +=(distance-2*radius) / 4*((circlePos[i+1].y - circlePos[i].y)/distance);;
shift[i].z += (distance-2*radius) / 4*((circlePos[i+1].z - circlePos[i].z)/distance);

shift[i+1].x = -shift[i].x;
shift[i+1].y = -shift[i].y;
shift[i+1].z = -shift[i].z;
}

should work this way (hopefully...)

this way every ball is going to stay at a distance 2*radius from the linked balls(which is what you want)

edit: oh, and after all also I implicitely use the position-last position approach, since when you update v you are just using position-lastposition

Â©hâ‚¬ck Ã¸ut Âµy stuÆ’Æ’ Ã¥t ragdollsoft.com
Sage
Posts: 1,066
Joined: 2004.07
Post: #19
I put that code in and now I get some weird outcomes. They're too hard to describe so I uploaded the code to my site so someone can help.

Edit: Scratch that. I forgot to fix the velocities based on the distance actually moved. You can still get the code if you want it (it doesn't work) though I don't know why you would.

Edit 2: I did update the file. There's just a weird glitch if you push a button or drag the mouse on the screen. I'm not sure why. I'm not sure what else to enhance my little system. Any ideas?

Edit 3: Forgot to mention, press P to pause/unpause the simulation.
Member
Posts: 749
Joined: 2003.01
Post: #20
Argh, I dunno... this is the nightmare of coding physics :-(

Ok, so if you're really into it you can work out how to handle collisions, rotations and everything of a rigid shape- not circle. I still havent go into that, my world is made by balls so far ;-)

or better try to turn your rope into a game

Â©hâ‚¬ck Ã¸ut Âµy stuÆ’Æ’ Ã¥t ragdollsoft.com
Sage
Posts: 1,066
Joined: 2004.07
Post: #21
I'd like to add more such as collisions and rotations and getting the rope to swing back and forth (as opposed to just falling and sitting straight up and down). I'm just not sure where to look for information as to how that all works.
Member
Posts: 749
Joined: 2003.01
Post: #22
hmmm, if the rope stays down instead of swinging you got something wrong... this algorithm should make a very realistic rope, you can also propagate waves in it.

Probably the velocity update is the problem

Or maybe try to delete the code that avoids the circles overlapping

Â©hâ‚¬ck Ã¸ut Âµy stuÆ’Æ’ Ã¥t ragdollsoft.com
Sage
Posts: 1,066
Joined: 2004.07
Post: #23
I'm not doing the check for overlaps anymore. Here's my entire circle updating code:
Code:
```- (void)updateCircles {     int i,j;     SEVector    shift[NUM_CIRCLES];     SEVector    tempVector;     SEVector    oldPos[NUM_CIRCLES];     float        tempFloat,tempFloat2;          //apply gravity to all of the circles except one     for(i = 0; i < NUM_CIRCLES - 1; i++)         circleVel[i].y -= GRAVITY * elapsedTime;          //add the velocities to the circles     for(i = 0; i < NUM_CIRCLES - 2; i++)     {         oldPos[i] = circlePos[i];         circlePos[i].x += circleVel[i].x * elapsedTime;         circlePos[i].y += circleVel[i].y * elapsedTime;         circlePos[i].z += circleVel[i].z * elapsedTime;     }          //figure out shifts for circles     for(i = 0; i < NUM_CIRCLES - 1; i++)     {         tempFloat = sqrt(pow(circlePos[i+1].x - circlePos[i].x,2) +                          pow(circlePos[i+1].y - circlePos[i].y,2) +                          pow(circlePos[i+1].z - circlePos[i].z,2));                  shift[i].x += ((tempFloat - (CIRCLE_RADIUS * 2)) / 4) * ((circlePos[i+1].x - circlePos[i].x) / tempFloat);         shift[i].y += ((tempFloat - (CIRCLE_RADIUS * 2)) / 4) * ((circlePos[i+1].y - circlePos[i].y) / tempFloat);         shift[i].z += ((tempFloat - (CIRCLE_RADIUS * 2)) / 4) * ((circlePos[i+1].z - circlePos[i].z) / tempFloat);                  shift[i+1].x = -shift[i].x;         shift[i+1].y = -shift[i].y;         shift[i+1].z = -shift[i].z;     }          //apply the shifts     for(i = 0; i < NUM_CIRCLES - 2; i++)     {         circlePos[i].x += shift[i].x;         circlePos[i].y += shift[i].y;         circlePos[i].z += shift[i].z;     }          //reset the velocities based on actual movement     for(i = 0; i < NUM_CIRCLES - 1; i++)     {         circleVel[i].x = circlePos[i].x - oldPos[i].x;         circleVel[i].y = circlePos[i].y - oldPos[i].y;         circleVel[i].z = circlePos[i].z - oldPos[i].z;     } }```
Member
Posts: 749
Joined: 2003.01
Post: #24

So there are two ways of doing this, WITH the "elapsedTime" or WITHOUT, if you do it WITH you gotta be careful:

you wrote

circleVel[i].x = circlePos[i].x - oldPos[i].x;

while it should be

circleVel[i].x = (circlePos[i].x - oldPos[i].x)/elapsedTime;

(and of course the same for y and z)

(so either you do

x=x+xv and then xv=currentx-oldx

either

x=x+xv*elapsedtime and then xv=(currentx-oldx)/elapsedtime,

while you mixed, i.e. you did

x=x+xv*elapsedtime and then xv=currentx-oldx
)

hope you finally get it working :-)

(then try to put the ability of grabbing balls with the mouse)

Â©hâ‚¬ck Ã¸ut Âµy stuÆ’Æ’ Ã¥t ragdollsoft.com
Sage
Posts: 1,066
Joined: 2004.07
Post: #25
Try downloading the files once and changing that part. When I do it, I get a real big mess of things. It doesn't work as planned but I don't have time to upload a new version to show you because I have work in the morning (12:30 am here, my work starts at 7 ).
Member
Posts: 749
Joined: 2003.01
Post: #26
sorry, I dont have a mac here, post your code again and I'm sure I'll spot something else :/

Â©hâ‚¬ck Ã¸ut Âµy stuÆ’Æ’ Ã¥t ragdollsoft.com
Sage
Posts: 1,066
Joined: 2004.07
Post: #27
Ok. I've updated my code so you can grab it here and check it out.
Sage
Posts: 1,066
Joined: 2004.07
Post: #28
Here's the code in case you don't want to download anything. It still doesn't swing or sway like real rope. Just falls from horizontal to vertical and sits there.
Code:
```- (void)updateCircles {     int i,j;     SEVector    shift[NUM_CIRCLES];     SEVector    tempVector;     SEVector    oldPos[NUM_CIRCLES];     float        tempFloat,tempFloat2;          //apply gravity to all of the circles except one     for(i = 0; i < NUM_CIRCLES - 1; i++)         circleVel[i].y -= GRAVITY * elapsedTime;          //add the velocities to the circles     for(i = 0; i < NUM_CIRCLES - 1; i++)     {         oldPos[i] = circlePos[i];         circlePos[i].x += circleVel[i].x * elapsedTime;         circlePos[i].y += circleVel[i].y * elapsedTime;         circlePos[i].z += circleVel[i].z * elapsedTime;     }          //figure out shifts for circles     for(i = 0; i < NUM_CIRCLES - 1; i++)     {         tempFloat = sqrt(pow(circlePos[i+1].x - circlePos[i].x,2) +                          pow(circlePos[i+1].y - circlePos[i].y,2) +                          pow(circlePos[i+1].z - circlePos[i].z,2));                  shift[i].x += ((tempFloat - (CIRCLE_RADIUS * 2)) / 4) * ((circlePos[i+1].x - circlePos[i].x) / tempFloat);         shift[i].y += ((tempFloat - (CIRCLE_RADIUS * 2)) / 4) * ((circlePos[i+1].y - circlePos[i].y) / tempFloat);         shift[i].z += ((tempFloat - (CIRCLE_RADIUS * 2)) / 4) * ((circlePos[i+1].z - circlePos[i].z) / tempFloat);                  shift[i+1].x = -shift[i].x;         shift[i+1].y = -shift[i].y;         shift[i+1].z = -shift[i].z;     }          //apply the shifts     for(i = 0; i < NUM_CIRCLES - 1; i++)     {         circlePos[i].x += shift[i].x;         circlePos[i].y += shift[i].y;         circlePos[i].z += shift[i].z;     }          //reset the velocities based on actual movement     for(i = 0; i < NUM_CIRCLES - 1; i++)     {         circleVel[i].x = circlePos[i].x - oldPos[i].x;         circleVel[i].y = circlePos[i].y - oldPos[i].y;         circleVel[i].z = circlePos[i].z - oldPos[i].z;     } }```

There's also some weird glitch where any keyboard input will cause the whole thing to jitter. Hard to explain. You'll just have to download the code and build it yourself. I think it might just be slowing the app down and causing the elapsedTime to jump a bit and cause the circles to move too much.

Thanks for all the help.
Member
Posts: 749
Joined: 2003.01
Post: #29
you wrote

circleVel[i].x = circlePos[i].x - oldPos[i].x;

while it should be

circleVel[i].x = (circlePos[i].x - oldPos[i].x)/elapsedTime;

(and of course the same for y and z)

If you say this does not work (it gets unstable), try deleting "elapsed time" from all the formulas (and also decreasing the gravity, o/w it would be too high), and see if that works, the system should be more stable.

(In this kind of stuff, if the elapsed time jumps from 1/60th of a second to 1/50th, you have big problems (caused by the velocity updating), that's why it's better to keep stuff "loop based", not "time based")\

If it's still unstable try putting

circleVel[i].x = (circlePos[i].x - oldPos[i].x)*0.99
(and of course the same for y and z)

And yes, probably the jumping thing is caused by the pressing buttons to change the "elapsed time"

Â©hâ‚¬ck Ã¸ut Âµy stuÆ’Æ’ Ã¥t ragdollsoft.com