Rope Physics
optimusp

This problem seems to be a doozy.

Does anyone know of any good rope physics tutorials (other than NeHe)?

I have the following code, but I'm not getting any swinging motion like a pendulum:

 1 #include 2 #include 3 bool up, down, left, right; 4 5 class rope{ 6 public: 7 class joint{ 8 public: 9 float x1,y1,x2,y2; 10 float velX,velY; 11 }joint[40]; 12 13 float seg_length; //length of segments between joints 14 float air_resistance; //air resistance [negating factor on gravity {9.8}] 15 float damping; //self-explanitory 16 float speed; //didn't know what else to name this 17 18 void deploy(); //initializes the rope 19 void update(bool, bool, bool, bool); //called every game-cycle 20 void draw(BITMAP *); 21 }rope[20]; 22 23 void rope::deploy() { 24 seg_length=5; 25 air_resistance=0.0; 26 damping=.10; 27 speed=0.2; 28 29 for(short i=0; i<40; i++) { 30 joint.x1=SCREEN_W/2; joint.y1=i*seg_length; 31 joint.x2=SCREEN_W/2; joint.y2=i*seg_length; 32 joint.velX=0; joint.velY=0; 33 } 34 }; 35 36 void rope::update(bool up, bool down, bool left, bool right) { 37 if (left) 38 { 39 joint[0].x1--; 40 } 41 if (right) 42 { 43 joint[0].x1++; 44 } 45 if (up) 46 { 47 joint[0].y1--; 48 } 49 if (down) 50 { 51 joint[0].y1++; 52 } 53 54 for(short i=0; i<40; i++) { 55 if (i != 0) 56 { 57 float vx1=joint[i-1].x1-joint.x1; //vector 1: diffrence between x's 58 float vy1=joint[i-1].y1-joint.y1; //vector 1: diffrence between y's 59 int vm1= (int)sqrt(ceil(vx1*vx1+vy1*vy1)); //vector 1: magnitude 60 int ve1= (int)vm1-(int)(seg_length/1); //vector 1: extention 61 62 float vx2=joint[i-1].x1-joint.x1; //vector 2: diffrence between x's 63 float vy2=joint[i-1].y1-joint.y1; //vector 2: diffrence between y's 64 int vm2= (int)sqrt(ceil(vx2*vx2+vy2*vy2)); //vector 2: magnitude 65 int ve2= (int)vm2- (int)seg_length; //vector 2: extention 66 67 float vx=(vx1/vm1*ve1)+(vx2/vm2*ve2); //x's reactant 68 float vy=(vy1/vm1*ve1)+(vy2/vm2*ve2)+9.8; //y's reactant 69 70 joint.velX=joint.velX*damping+(vx*speed); //set velocity x accordingly 71 joint.velY=joint.velY*damping+(vy*speed); //set velocity y accordingly 72 joint.x2=joint.x1+joint.velX; //buffer x 73 joint.y2=joint.y1+joint.velY; //buffer y 74 joint.x1=joint.x2; //copy buffer to physical 75 joint.y1=joint.y2; //copy buffer to physical 76 } 77 } 78 }; 79 80 void rope::draw(BITMAP *buffer) { 81 for(short i=0; i<40; i++) { 82 //draw joint and lines between 83 if (i == 0) 84 { 85 circlefill(buffer, (int)joint.x1, (int)joint.y1, 2, makecol(255,255,255)); 86 } else { 87 circlefill(buffer, (int)joint.x1, (int)joint.y1, 2, makecol(i*2,i*2,255)); 88 } 89 if (i != 0) 90 { 91 line(buffer, (int)joint.x1, (int)joint.y1,(int)joint[i-1].x1, (int)joint[i-1].y1, makecol(i*2,i*2,255)); 92 } 93 } 94 }; 95 96 void init(); 97 void deinit(); 98 99 int main() { 100 init(); 101 BITMAP *buffer = NULL; 102 buffer = create_bitmap(640,480); 103 104 105 rope[0].deploy(); 106 107 while (!key[KEY_ESC]) 108 { 109 if (key[KEY_U]) 110 { 111 //rope[0].update(); 112 } 113 if (key[KEY_D]) 114 { 115 rope[0].deploy(); 116 } 117 118 if (key[KEY_LEFT]) 119 { 120 left = true; 121 } 122 123 if (key[KEY_RIGHT]) 124 { 125 right = true; 126 } 127 128 if (key[KEY_UP]) 129 { 130 up = true; 131 } 132 133 if (key[KEY_DOWN]) 134 { 135 down = true; 136 } 137 138 rope[0].update(up, down, left, right); 139 rope[0].draw(buffer); 140 blit(buffer, screen, 0,0,0,0,640,480);//Draw the buffer to the screen 141 clear_bitmap(buffer); // Clear the contents of the buffer bitmap 142 left = false; 143 right = false; 144 up = false; 145 down = false; 146 } 147 148 deinit(); 149 return 0; 150 } 151 END_OF_MAIN() 152 153 void init() { 154 int depth, res; 155 allegro_init(); 156 depth = desktop_color_depth(); 157 if (depth == 0) depth = 32; 158 set_color_depth(depth); 159 res = set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0); 160 if (res != 0) { 161 allegro_message(allegro_error); 162 exit(-1); 163 } 164 165 install_timer(); 166 install_keyboard(); 167 install_mouse(); 168 /* add other initializations here */ 169 170 } 171 172 void deinit() { 173 clear_keybuf(); 174 /* add other deinitializations here */ 175 }

By the way, this code is an edited version from the code on this thread:

Dustin Dettmer
Quote:

pendulum

pendulum physics is about one of (in my book) hardest problems to solve. A bunch of pendulums on end will take too much CPU time and is a bad way to do a rope.

But on the other hand I've never actually solved it. So I have no idea what I'm talking about.

http://en.wikipedia.org/wiki/Pendulum_%28mathematics%29

nonnus29
Quote:

pendulum physics is about one of (in my book) hardest problems to solve. A bunch of pendulums on end will take too much CPU time and is a bad way to do a rope.

Naw, it's easy. This is what verlet integration excels at. Google for Chris Heckers physics tutorials.

Edit; wow that's almost exactly what I said in the other thread. Weird. I'm wasting WAAAY to much time on here....

Zaphos

The Advanced Character Physics article covers what you'd want -- a rope can be modeled nicely as a line of particles connected by distance constraints.

optimusp

Thank's guys. I'm using that exact article you just mentioned. I've been reading over it the past couple hours and I'll try to implement it now.

Here is what I have prior to implementing the math from that article. Very basic stuff, but some neat effects. I'm using Dev-C++. You can just post this into a new project, and it should compile:

1#include <allegro.h> 2#include <math.h> 3bool up, down, left, right; 4 5class rope{ 6public: 7 class joint{ 8 public: 9 float x1,y1,x2,y2; 10 float velX,velY; 11 12 }joint[100]; 13 14 float real_length; 15 float seg_length; //length of segments between joints 16 float air_resistance; //air resistance [negating factor on gravity {9.8}] 17 float damping; //self-explanitory 18 float speed; //didn't know what else to name this 19 float gravity; 20 bool gravity_on; 21 22 void deploy(); //initializes the rope 23 void update(bool, bool, bool, bool); //called every game-cycle 24 void draw(BITMAP *); 25}rope[20]; 26 27void rope::deploy() { 28 seg_length=5; 29 air_resistance=0.0; 30 damping= 0.0; 31 speed= .41; 32 gravity = .0; 33 34 for(short i=0; i<100; i++) { 35 joint<i>.x1=SCREEN_W/2 + (i*3); joint<i>.y1=i*seg_length; 36 joint<i>.x2=SCREEN_W/2 + (i*3); joint<i>.y2=i*seg_length; 37 joint<i>.velX=0; joint<i>.velY=0; 38 } 39}; 40 41void rope::update(bool up, bool down, bool left, bool right) { 42 if (left) 43 { 44 joint[0].x1--; 45 } 46 if (right) 47 { 48 joint[0].x1++; 49 } 50 if (up) 51 { 52 joint[0].y1--; 53 } 54 if (down) 55 { 56 joint[0].y1++; 57 } 58 59 for(short i=0; i<100; i++) { 60 if (i != 0) 61 { 62 float vx1=joint[i-1].x1-joint<i>.x1; //vector 1: diffrence between x's 63 float vy1=joint[i-1].y1-joint<i>.y1; //vector 1: diffrence between y's 64 int vm1= (int)sqrt(ceil(vx1*vx1+vy1*vy1)); //vector 1: magnitude 65 int ve1= (int)vm1-(int)(seg_length/1); //vector 1: extention 66 67 float vx2=joint[i-1].x1-joint<i>.x1; //vector 2: diffrence between x's 68 float vy2=joint[i-1].y1-joint<i>.y1; //vector 2: diffrence between y's 69 int vm2= (int)sqrt(ceil(vx2*vx2+vy2*vy2)); //vector 2: magnitude 70 int ve2= (int)vm2- (int)seg_length; //vector 2: extention 71 72 float vx = (vx1 / vm1 * ve1) + (vx2 / vm2 * ve2); //x's reactant 73 float vy = (vy1 / vm1 * ve1) + (vy2 / vm2 * ve2) + gravity; //y's reactant 74 75 joint<i>.velX = joint<i>.velX * damping + (vx * speed); //set velocity x accordingly 76 joint<i>.velY = joint<i>.velY * damping + (vy * speed); //set velocity y accordingly 77 joint<i>.x2 = joint<i>.x1 + joint<i>.velX; //buffer x 78 joint<i>.y2 = joint<i>.y1 + joint<i>.velY; //buffer y 79 joint<i>.x1 = joint<i>.x2; //copy buffer to physical 80 joint<i>.y1 = joint<i>.y2; //copy buffer to physical 81 } else { 82 83 float vx1=joint<i>.x1; //vector 1: diffrence between x's 84 float vy1=joint<i>.y1; //vector 1: diffrence between y's 85 int vm1= (int)sqrt(ceil(vx1*vx1+vy1*vy1)); //vector 1: magnitude 86 int ve1= (int)vm1-(int)(seg_length/1); //vector 1: extention 87 88 float vx2=joint<i>.x1; //vector 2: diffrence between x's 89 float vy2=joint<i>.y1; //vector 2: diffrence between y's 90 int vm2= (int)sqrt(ceil(vx2*vx2+vy2*vy2)); //vector 2: magnitude 91 int ve2= (int)vm2- (int)seg_length; //vector 2: extention 92 93 float vx = 0; //x's reactant 94 float vy = gravity; //y's reactant 95 96 joint<i>.velX = joint<i>.velX * damping+(vx * speed); //set velocity x accordingly 97 joint<i>.velY = joint<i>.velY - gravity; //set velocity y accordingly 98 99 joint<i>.x2 = joint<i>.x1+joint<i>.velX; //buffer x 100 joint<i>.y2 = joint<i>.y1 - joint<i>.velY; //buffer y 101 joint<i>.x1 = joint<i>.x2; //copy buffer to physical 102 joint<i>.y1 = joint<i>.y2; //copy buffer to physical 103 } 104 if (joint<i>.y1 > (SCREEN_H-50)) { 105 joint<i>.velY = abs(joint<i>.velY) * (1 - damping); 106 joint<i>.y2 = SCREEN_H-50; 107 joint<i>.y1 = SCREEN_H-50; 108 } 109 } 110 111 if (key[KEY_G]) 112 { 113 if (gravity_on) 114 { 115 gravity_on = false; 116 } else { 117 gravity_on = true; 118 } 119 } 120}; 121 122void rope::draw(BITMAP *buffer) { 123 for(short i=0; i<100; i++) { 124 //draw joint and lines between 125 if (i == 0) 126 { 127 circlefill(buffer, (int)joint<i>.x1, (int)joint<i>.y1, 2, makecol(255,255,255)); 128 } else { 129 //circlefill(buffer, (int)joint<i>.x1, (int)joint<i>.y1, 2, makecol(i*2,i*2,255)); 130 } 131 if (i != 0) 132 { 133 line(buffer, (int)joint<i>.x1, (int)joint<i>.y1,(int)joint[i-1].x1, (int)joint[i-1].y1, makecol(i*2,i*2,255)); 134 this[0].real_length = this[0].real_length + (sqrt(pow(joint<i>.x1 - joint[i-1].x1, 2) + pow(joint<i>.y1 - joint[i-1].y1, 2))); 135 } 136 } 137 textprintf_ex(buffer, font, 10, SCREEN_H-10, makecol(255, 100, 200), -1, "y1: %f", joint[0].y1); 138 textprintf_ex(buffer, font, 10, SCREEN_H-20, makecol(255, 100, 200), -1, "velY: %f", joint[0].velY); 139 textprintf_ex(buffer, font, 10, SCREEN_H-30, makecol(255, 100, 200), -1, "y1: %f", this[0].real_length); 140 this[0].real_length = 0; 141}; 142 143void init(); 144void deinit(); 145 146int main() { 147 init(); 148 BITMAP *buffer = NULL; 149 FONT *font = NULL; 150 buffer = create_bitmap(640,480); 151 152 153 rope[0].deploy(); 154 155 while (!key[KEY_ESC]) 156 { 157 if (key[KEY_U]) 158 { 159 //rope[0].update(); 160 } 161 if (key[KEY_D]) 162 { 163 rope[0].deploy(); 164 } 165 166 if (key[KEY_LEFT]) 167 { 168 left = true; 169 } 170 171 if (key[KEY_RIGHT]) 172 { 173 right = true; 174 } 175 176 if (key[KEY_UP]) 177 { 178 up = true; 179 } 180 181 if (key[KEY_DOWN]) 182 { 183 down = true; 184 } 185 186 rope[0].update(up, down, left, right); 187 188 189 rectfill(buffer, 0, SCREEN_H, SCREEN_W, SCREEN_H - 50, makecol(100,100,100)); //ground 190 rope[0].draw(buffer); 191 blit(buffer, screen, 0,0,0,0,640,480);//Draw the buffer to the screen 192 clear_bitmap(buffer); // Clear the contents of the buffer bitmap 193 left = false; 194 right = false; 195 up = false; 196 down = false; 197 } 198 199 deinit(); 200 return 0; 201} 202END_OF_MAIN() 203 204void init() { 205 int depth, res; 206 allegro_init(); 207 depth = desktop_color_depth(); 208 if (depth == 0) depth = 32; 209 set_color_depth(depth); 210 res = set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0); 211 if (res != 0) { 212 allegro_message(allegro_error); 213 exit(-1); 214 } 215 216 install_timer(); 217 install_keyboard(); 218 install_mouse(); 219 /* add other initializations here */ 220 221} 222 223void deinit() { 224 clear_keybuf(); 225 /* add other deinitializations here */ 226}

I'll post again with a zip file once I've gotten the rigid body stuff implemented.

BTW:

I'd like to thank X-G for this wonderful [url http://awiki.tomasu.org/bin/view/Main/Vector3D#xgl_vector_h]Vector Library[/url]. It's proved to be very useful so far.

Goalie Ca

i calculated gravity to within .05m/s^2 using a pendulum once. kinda cool.

anyways back to the question. what's the application? Its really good to cheat with physics and i want to know how much we can cheat.

Neil Walker

What you need to do is allow any joint to be moved, this will allow you pull the rope from any point, including the last one to mimic swinging, or if on a joint half way down you could make it look as though the rope is tied to something and just out of reach of the player.

optimusp

Update:

I've got a semi-working model. It's certainly mimics rope realistically, but I'm going to put some more accurate math behind it. You can adjust the number of joints and length in the code if you like.

http://www.findur.com/rope3.zip

This code can also be used for rigid body collisions. That's what I'll be working on next. Hopefully I'll have another update for you soon.

Thanks for the help guys.

Edit: By the way, a pre-compiled exe is included. Use the arrow keys to move the lead joint. Use the "U" key to constrain the lead joint to a fixed position (this will allow you to see the swinging in full effect).

If you mess with the number of joints and the segment length, you'll notice that there is a lot of "spingyness". I'm trying to correct this. Or at the very least, make it something that's adjustable.

Frank Drebin

looks cool!

optimusp

Thanks.

After I get it going, I'm going to use it to build and accurate 3d human body representation. Then I'll use a genetically modified neural network to teach it how to walk.

If that goes well, then I'll start to move into other more complicated maneuvers.

This is all for my senior Computer Science project. And I'm still a sophomore!