1 2 // written in the D programming language 3 4 module samples.Joints; 5 6 import dchip.all; 7 8 import samples.ChipmunkDemo; 9 10 import std.math; 11 12 static cpSpace *space; 13 14 enum M_PI = PI; 15 enum M_PI_2 = PI*0.5f; 16 17 static cpBody * 18 addBall(cpVect pos, cpVect boxOffset) 19 { 20 cpFloat radius = 15.0f; 21 cpFloat mass = 1.0f; 22 cpBody *_body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForCircle(mass, 0.0f, radius, cpvzero))); 23 _body.p = cpvadd(pos, boxOffset); 24 25 cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(_body, radius, cpvzero)); 26 shape.e = 0.0f; shape.u = 0.7f; 27 28 return _body; 29 } 30 31 static cpBody * 32 addLever(cpVect pos, cpVect boxOffset) 33 { 34 cpFloat mass = 1.0f; 35 cpVect a = cpv(0, 15); 36 cpVect b = cpv(0, -15); 37 38 cpBody *_body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForSegment(mass, a, b))); 39 _body.p = cpvadd(pos, cpvadd(boxOffset, cpv(0, -15))); 40 41 cpShape *shape = cpSpaceAddShape(space, cpSegmentShapeNew(_body, a, b, 5.0f)); 42 shape.e = 0.0f; shape.u = 0.7f; 43 44 return _body; 45 } 46 47 static cpBody * 48 addBar(cpVect pos, cpVect boxOffset) 49 { 50 cpFloat mass = 2.0f; 51 cpVect a = cpv(0, 30); 52 cpVect b = cpv(0, -30); 53 54 cpBody *_body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForSegment(mass, a, b))); 55 _body.p = cpvadd(pos, boxOffset); 56 57 cpShape *shape = cpSpaceAddShape(space, cpSegmentShapeNew(_body, a, b, 5.0f)); 58 shape.e = 0.0f; shape.u = 0.7f; 59 60 return _body; 61 } 62 63 static cpBody * 64 addWheel(cpVect pos, cpVect boxOffset) 65 { 66 cpFloat radius = 15.0f; 67 cpFloat mass = 1.0f; 68 cpBody *_body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForCircle(mass, 0.0f, radius, cpvzero))); 69 _body.p = cpvadd(pos, boxOffset); 70 71 cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(_body, radius, cpvzero)); 72 shape.e = 0.0f; shape.u = 0.7f; 73 shape.group = 1; // use a group to keep the car parts from colliding 74 75 return _body; 76 } 77 78 static cpBody * 79 addChassis(cpVect pos, cpVect boxOffset) 80 { 81 int num = 4; 82 cpVect verts[] = [ 83 cpv(-40,-15), 84 cpv(-40, 15), 85 cpv( 40, 15), 86 cpv( 40,-15), 87 ]; 88 89 90 cpFloat mass = 5.0f; 91 cpBody *_body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForPoly(mass, num, verts.ptr, cpvzero))); 92 _body.p = cpvadd(pos, boxOffset); 93 94 cpShape *shape = cpSpaceAddShape(space, cpPolyShapeNew(_body, num, verts.ptr, cpvzero)); 95 shape.e = 0.0f; shape.u = 0.7f; 96 shape.group = 1; // use a group to keep the car parts from colliding 97 98 return _body; 99 } 100 101 static cpSpace * 102 init() 103 { 104 space = cpSpaceNew(); 105 space.iterations = 10; 106 space.gravity = cpv(0, -100); 107 space.sleepTimeThreshold = 0.5f; 108 109 cpBody *staticBody = space.staticBody; 110 cpShape *shape; 111 112 shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,240), cpv(320,240), 0.0f)); 113 shape.e = 1.0f; shape.u = 1.0f; 114 shape.layers = NOT_GRABABLE_MASK; 115 116 shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,120), cpv(320,120), 0.0f)); 117 shape.e = 1.0f; shape.u = 1.0f; 118 shape.layers = NOT_GRABABLE_MASK; 119 120 shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,0), cpv(320,0), 0.0f)); 121 shape.e = 1.0f; shape.u = 1.0f; 122 shape.layers = NOT_GRABABLE_MASK; 123 124 shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-120), cpv(320,-120), 0.0f)); 125 shape.e = 1.0f; shape.u = 1.0f; 126 shape.layers = NOT_GRABABLE_MASK; 127 128 shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(320,-240), 0.0f)); 129 shape.e = 1.0f; shape.u = 1.0f; 130 shape.layers = NOT_GRABABLE_MASK; 131 132 133 shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(-320,240), 0.0f)); 134 shape.e = 1.0f; shape.u = 1.0f; 135 shape.layers = NOT_GRABABLE_MASK; 136 137 shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-160,-240), cpv(-160,240), 0.0f)); 138 shape.e = 1.0f; shape.u = 1.0f; 139 shape.layers = NOT_GRABABLE_MASK; 140 141 shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(0,-240), cpv(0,240), 0.0f)); 142 shape.e = 1.0f; shape.u = 1.0f; 143 shape.layers = NOT_GRABABLE_MASK; 144 145 shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(160,-240), cpv(160,240), 0.0f)); 146 shape.e = 1.0f; shape.u = 1.0f; 147 shape.layers = NOT_GRABABLE_MASK; 148 149 shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(320,-240), cpv(320,240), 0.0f)); 150 shape.e = 1.0f; shape.u = 1.0f; 151 shape.layers = NOT_GRABABLE_MASK; 152 153 cpVect boxOffset; 154 cpBody *body1; 155 cpBody *body2; 156 157 cpVect posA = cpv( 50, 60); 158 cpVect posB = cpv(110, 60); 159 160 // Pin Joints - Link shapes with a solid bar or pin. 161 // Keeps the anchor points the same distance apart from when the joint was created. 162 boxOffset = cpv(-320, -240); 163 body1 = addBall(posA, boxOffset); 164 body2 = addBall(posB, boxOffset); 165 cpSpaceAddConstraint(space, cpPinJointNew(body1, body2, cpv(15,0), cpv(-15,0))); 166 167 // Slide Joints - Like pin joints but with a min/max distance. 168 // Can be used for a cheap approximation of a rope. 169 boxOffset = cpv(-160, -240); 170 body1 = addBall(posA, boxOffset); 171 body2 = addBall(posB, boxOffset); 172 cpSpaceAddConstraint(space, cpSlideJointNew(body1, body2, cpv(15,0), cpv(-15,0), 20.0f, 40.0f)); 173 174 // Pivot Joints - Holds the two anchor points together. Like a swivel. 175 boxOffset = cpv(0, -240); 176 body1 = addBall(posA, boxOffset); 177 body2 = addBall(posB, boxOffset); 178 cpSpaceAddConstraint(space, cpPivotJointNew(body1, body2, cpvadd(boxOffset, cpv(80,60)))); 179 // cpPivotJointNew() takes it's anchor parameter in world coordinates. The anchors are calculated from that 180 // cpPivotJointNew2() lets you specify the two anchor points explicitly 181 182 // Groove Joints - Like a pivot joint, but one of the anchors is a line segment that the pivot can slide in 183 boxOffset = cpv(160, -240); 184 body1 = addBall(posA, boxOffset); 185 body2 = addBall(posB, boxOffset); 186 cpSpaceAddConstraint(space, cpGrooveJointNew(body1, body2, cpv(30,30), cpv(30,-30), cpv(-30,0))); 187 188 // Damped Springs 189 boxOffset = cpv(-320, -120); 190 body1 = addBall(posA, boxOffset); 191 body2 = addBall(posB, boxOffset); 192 cpSpaceAddConstraint(space, cpDampedSpringNew(body1, body2, cpv(15,0), cpv(-15,0), 20.0f, 5.0f, 0.3f)); 193 194 // Damped Rotary Springs 195 boxOffset = cpv(-160, -120); 196 body1 = addBar(posA, boxOffset); 197 body2 = addBar(posB, boxOffset); 198 // Add some pin joints to hold the circles in place. 199 cpSpaceAddConstraint(space, cpPivotJointNew(body1, staticBody, cpvadd(boxOffset, posA))); 200 cpSpaceAddConstraint(space, cpPivotJointNew(body2, staticBody, cpvadd(boxOffset, posB))); 201 cpSpaceAddConstraint(space, cpDampedRotarySpringNew(body1, body2, 0.0f, 3000.0f, 60.0f)); 202 203 // Rotary Limit Joint 204 boxOffset = cpv(0, -120); 205 body1 = addLever(posA, boxOffset); 206 body2 = addLever(posB, boxOffset); 207 // Add some pin joints to hold the circles in place. 208 cpSpaceAddConstraint(space, cpPivotJointNew(body1, staticBody, cpvadd(boxOffset, posA))); 209 cpSpaceAddConstraint(space, cpPivotJointNew(body2, staticBody, cpvadd(boxOffset, posB))); 210 // Hold their rotation within 90 degrees of each other. 211 cpSpaceAddConstraint(space, cpRotaryLimitJointNew(body1, body2, -M_PI_2, M_PI_2)); 212 213 // Ratchet Joint - A rotary ratchet, like a socket wrench 214 boxOffset = cpv(160, -120); 215 body1 = addLever(posA, boxOffset); 216 body2 = addLever(posB, boxOffset); 217 // Add some pin joints to hold the circles in place. 218 cpSpaceAddConstraint(space, cpPivotJointNew(body1, staticBody, cpvadd(boxOffset, posA))); 219 cpSpaceAddConstraint(space, cpPivotJointNew(body2, staticBody, cpvadd(boxOffset, posB))); 220 // Ratchet every 90 degrees 221 cpSpaceAddConstraint(space, cpRatchetJointNew(body1, body2, 0.0f, M_PI_2)); 222 223 // Gear Joint - Maintain a specific angular velocity ratio 224 boxOffset = cpv(-320, 0); 225 body1 = addBar(posA, boxOffset); 226 body2 = addBar(posB, boxOffset); 227 // Add some pin joints to hold the circles in place. 228 cpSpaceAddConstraint(space, cpPivotJointNew(body1, staticBody, cpvadd(boxOffset, posA))); 229 cpSpaceAddConstraint(space, cpPivotJointNew(body2, staticBody, cpvadd(boxOffset, posB))); 230 // Force one to sping 2x as fast as the other 231 cpSpaceAddConstraint(space, cpGearJointNew(body1, body2, 0.0f, 2.0f)); 232 233 // Simple Motor - Maintain a specific angular relative velocity 234 boxOffset = cpv(-160, 0); 235 body1 = addBar(posA, boxOffset); 236 body2 = addBar(posB, boxOffset); 237 // Add some pin joints to hold the circles in place. 238 cpSpaceAddConstraint(space, cpPivotJointNew(body1, staticBody, cpvadd(boxOffset, posA))); 239 cpSpaceAddConstraint(space, cpPivotJointNew(body2, staticBody, cpvadd(boxOffset, posB))); 240 // Make them spin at 1/2 revolution per second in relation to each other. 241 cpSpaceAddConstraint(space, cpSimpleMotorNew(body1, body2, M_PI)); 242 243 // Make a car with some nice soft suspension 244 boxOffset = cpv(0, 0); 245 cpBody *wheel1 = addWheel(posA, boxOffset); 246 cpBody *wheel2 = addWheel(posB, boxOffset); 247 cpBody *chassis = addChassis(cpv(80, 100), boxOffset); 248 249 cpSpaceAddConstraint(space, cpGrooveJointNew(chassis, wheel1, cpv(-30, -10), cpv(-30, -40), cpvzero)); 250 cpSpaceAddConstraint(space, cpGrooveJointNew(chassis, wheel2, cpv( 30, -10), cpv( 30, -40), cpvzero)); 251 252 cpSpaceAddConstraint(space, cpDampedSpringNew(chassis, wheel1, cpv(-30, 0), cpvzero, 50.0f, 20.0f, 1.5f)); 253 cpSpaceAddConstraint(space, cpDampedSpringNew(chassis, wheel2, cpv( 30, 0), cpvzero, 50.0f, 20.0f, 1.5f)); 254 255 return space; 256 } 257 258 static void 259 update(int ticks) 260 { 261 cpSpaceStep(space, 1.0f/60.0f); 262 } 263 264 static void 265 destroy() 266 { 267 ChipmunkDemoFreeSpaceChildren(space); 268 cpSpaceFree(space); 269 } 270 271 chipmunkDemo Joints = { 272 "Joints and Constraints", 273 null, 274 &init, 275 &update, 276 &destroy, 277 };