1 /* 2 * Copyright (c) 2007-2013 Scott Lembcke and Howling Moon Software 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a copy 5 * of this software and associated documentation files (the "Software"), to deal 6 * in the Software without restriction, including without limitation the rights 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 * copies of the Software, and to permit persons to whom the Software is 9 * furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 */ 22 module demo.TheoJansen; 23 24 import core.stdc.stdlib; 25 26 import std.math; 27 28 alias M_PI_2 = PI_2; 29 30 import demo.dchip; 31 32 import demo.ChipmunkDebugDraw; 33 import demo.ChipmunkDemo; 34 import demo.types; 35 36 /* 37 * The previous WalkBot demo I designed was fairly disappointing, so I implemented 38 * the mechanism that Theo Jansen uses in his kinetic sculptures. Brilliant. 39 * Read more here: http://en.wikipedia.org/wiki/Theo_Jansen 40 */ 41 42 cpConstraint* motor; 43 44 void update(cpSpace* space, double dt) 45 { 46 cpFloat coef = (2.0f + ChipmunkDemoKeyboard.y) / 3.0f; 47 cpFloat rate = ChipmunkDemoKeyboard.x * 10.0f * coef; 48 cpSimpleMotorSetRate(motor, rate); 49 cpConstraintSetMaxForce(motor, (rate) ? 100000.0f : 0.0f); 50 51 cpSpaceStep(space, dt); 52 } 53 54 cpFloat seg_radius = 3.0f; 55 56 void make_leg(cpSpace* space, cpFloat side, cpFloat offset, cpBody* chassis, cpBody* crank, cpVect anchor) 57 { 58 cpVect a, b; 59 cpShape* shape; 60 61 cpFloat leg_mass = 1.0f; 62 63 // make leg 64 a = cpvzero, b = cpv(0.0f, side); 65 cpBody* upper_leg = cpSpaceAddBody(space, cpBodyNew(leg_mass, cpMomentForSegment(leg_mass, a, b))); 66 cpBodySetPos(upper_leg, cpv(offset, 0.0f)); 67 68 shape = cpSpaceAddShape(space, cpSegmentShapeNew(upper_leg, a, b, seg_radius)); 69 cpShapeSetGroup(shape, 1); 70 71 cpSpaceAddConstraint(space, cpPivotJointNew2(chassis, upper_leg, cpv(offset, 0.0f), cpvzero)); 72 73 // lower leg 74 a = cpvzero, b = cpv(0.0f, -1.0f * side); 75 cpBody* lower_leg = cpSpaceAddBody(space, cpBodyNew(leg_mass, cpMomentForSegment(leg_mass, a, b))); 76 cpBodySetPos(lower_leg, cpv(offset, -side)); 77 78 shape = cpSpaceAddShape(space, cpSegmentShapeNew(lower_leg, a, b, seg_radius)); 79 cpShapeSetGroup(shape, 1); 80 81 shape = cpSpaceAddShape(space, cpCircleShapeNew(lower_leg, seg_radius * 2.0f, b)); 82 cpShapeSetGroup(shape, 1); 83 cpShapeSetElasticity(shape, 0.0f); 84 cpShapeSetFriction(shape, 1.0f); 85 86 cpSpaceAddConstraint(space, cpPinJointNew(chassis, lower_leg, cpv(offset, 0.0f), cpvzero)); 87 88 cpSpaceAddConstraint(space, cpGearJointNew(upper_leg, lower_leg, 0.0f, 1.0f)); 89 90 cpConstraint* constraint; 91 cpFloat diag = cpfsqrt(side * side + offset * offset); 92 93 constraint = cpSpaceAddConstraint(space, cpPinJointNew(crank, upper_leg, anchor, cpv(0.0f, side))); 94 cpPinJointSetDist(constraint, diag); 95 96 constraint = cpSpaceAddConstraint(space, cpPinJointNew(crank, lower_leg, anchor, cpvzero)); 97 cpPinJointSetDist(constraint, diag); 98 } 99 100 cpSpace* init() 101 { 102 ChipmunkDemoMessageString = "Use the arrow keys to control the machine.".dup; 103 104 cpSpace* space = cpSpaceNew(); 105 cpSpaceSetIterations(space, 20); 106 cpSpaceSetGravity(space, cpv(0, -500)); 107 108 cpBody * staticBody = cpSpaceGetStaticBody(space); 109 cpShape* shape; 110 cpVect a, b; 111 112 // Create segments around the edge of the screen. 113 shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320, -240), cpv(-320, 240), 0.0f)); 114 cpShapeSetElasticity(shape, 1.0f); 115 cpShapeSetFriction(shape, 1.0f); 116 cpShapeSetLayers(shape, NOT_GRABABLE_MASK); 117 118 shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(320, -240), cpv(320, 240), 0.0f)); 119 cpShapeSetElasticity(shape, 1.0f); 120 cpShapeSetFriction(shape, 1.0f); 121 cpShapeSetLayers(shape, NOT_GRABABLE_MASK); 122 123 shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320, -240), cpv(320, -240), 0.0f)); 124 cpShapeSetElasticity(shape, 1.0f); 125 cpShapeSetFriction(shape, 1.0f); 126 cpShapeSetLayers(shape, NOT_GRABABLE_MASK); 127 128 cpFloat offset = 30.0f; 129 130 // make chassis 131 cpFloat chassis_mass = 2.0f; 132 a = cpv(-offset, 0.0f), b = cpv(offset, 0.0f); 133 cpBody* chassis = cpSpaceAddBody(space, cpBodyNew(chassis_mass, cpMomentForSegment(chassis_mass, a, b))); 134 135 shape = cpSpaceAddShape(space, cpSegmentShapeNew(chassis, a, b, seg_radius)); 136 cpShapeSetGroup(shape, 1); 137 138 // make crank 139 cpFloat crank_mass = 1.0f; 140 cpFloat crank_radius = 13.0f; 141 cpBody* crank = cpSpaceAddBody(space, cpBodyNew(crank_mass, cpMomentForCircle(crank_mass, crank_radius, 0.0f, cpvzero))); 142 143 shape = cpSpaceAddShape(space, cpCircleShapeNew(crank, crank_radius, cpvzero)); 144 cpShapeSetGroup(shape, 1); 145 146 cpSpaceAddConstraint(space, cpPivotJointNew2(chassis, crank, cpvzero, cpvzero)); 147 148 cpFloat side = 30.0f; 149 150 int num_legs = 2; 151 152 for (int i = 0; i < num_legs; i++) 153 { 154 make_leg(space, side, offset, chassis, crank, cpvmult(cpvforangle(cast(cpFloat)(2 * i + 0) / cast(cpFloat)num_legs * M_PI), crank_radius)); 155 make_leg(space, side, -offset, chassis, crank, cpvmult(cpvforangle(cast(cpFloat)(2 * i + 1) / cast(cpFloat)num_legs * M_PI), crank_radius)); 156 } 157 158 motor = cpSpaceAddConstraint(space, cpSimpleMotorNew(chassis, crank, 6.0f)); 159 160 return space; 161 } 162 163 void destroy(cpSpace* space) 164 { 165 ChipmunkDemoFreeSpaceChildren(space); 166 cpSpaceFree(space); 167 } 168 169 ChipmunkDemo TheoJansen = { 170 "Theo Jansen Machine", 171 1.0 / 180.0, 172 &init, 173 &update, 174 &ChipmunkDemoDefaultDrawImpl, 175 &destroy, 176 };