Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Rope Physics

This thread is locked; no one can reply to it. rss feed Print
Rope Physics
optimusp
Member #7,858
October 2006

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 <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 }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 
23void 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<i>.x1=SCREEN_W/2; joint<i>.y1=i*seg_length;
31 joint<i>.x2=SCREEN_W/2; joint<i>.y2=i*seg_length;
32 joint<i>.velX=0; joint<i>.velY=0;
33 }
34};
35 
36void 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<i>.x1; //vector 1: diffrence between x's
58 float vy1=joint[i-1].y1-joint<i>.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<i>.x1; //vector 2: diffrence between x's
63 float vy2=joint[i-1].y1-joint<i>.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<i>.velX=joint<i>.velX*damping+(vx*speed); //set velocity x accordingly
71 joint<i>.velY=joint<i>.velY*damping+(vy*speed); //set velocity y accordingly
72 joint<i>.x2=joint<i>.x1+joint<i>.velX; //buffer x
73 joint<i>.y2=joint<i>.y1+joint<i>.velY; //buffer y
74 joint<i>.x1=joint<i>.x2; //copy buffer to physical
75 joint<i>.y1=joint<i>.y2; //copy buffer to physical
76 }
77 }
78};
79 
80void 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<i>.x1, (int)joint<i>.y1, 2, makecol(255,255,255));
86 } else {
87 circlefill(buffer, (int)joint<i>.x1, (int)joint<i>.y1, 2, makecol(i*2,i*2,255));
88 }
89 if (i != 0)
90 {
91 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));
92 }
93 }
94};
95 
96void init();
97void deinit();
98 
99int 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}
151END_OF_MAIN()
152 
153void 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 
172void 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:
http://www.allegro.cc/forums/thread/574094

ImLeftFooted
Member #3,935
October 2003
avatar

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.

For a walk-through on the pendulum math, read its wikipedia page:
http://en.wikipedia.org/wiki/Pendulum_%28mathematics%29

nonnus29
Member #2,606
August 2002
avatar

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
Member #1,468
August 2001

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
Member #7,858
October 2006

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:

#SelectExpand
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
Member #2,579
July 2002
avatar

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.

-------------
Bah weep granah weep nini bong!

Neil Walker
Member #210
April 2000
avatar

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.

Neil.
MAME Cabinet Blog / AXL LIBRARY (a games framework) / AXL Documentation and Tutorial

wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie

optimusp
Member #7,858
October 2006

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).

Edit: Added a better build.

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
Member #2,987
December 2002
avatar

optimusp
Member #7,858
October 2006

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!

Go to: