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.Crane; 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 static cpBody* dollyBody = null; 37 38 // Constraint used as a servo motor to move the dolly back and forth. 39 static cpConstraint* dollyServo = null; 40 41 // Constraint used as a winch motor to lift the load. 42 static cpConstraint* winchServo = null; 43 44 // Temporary joint used to hold the hook to the load. 45 static cpConstraint* hookJoint = null; 46 47 static void update(cpSpace* space, double dt) 48 { 49 // Set the first anchor point (the one attached to the static body) of the dolly servo to the mouse's x position. 50 cpPivotJointSetAnchr1(dollyServo, cpv(ChipmunkDemoMouse.x, 100)); 51 52 // Set the max length of the winch servo to match the mouse's height. 53 cpSlideJointSetMax(winchServo, cpfmax(100 - ChipmunkDemoMouse.y, 50)); 54 55 if (hookJoint && ChipmunkDemoRightClick) 56 { 57 cpSpaceRemoveConstraint(space, hookJoint); 58 cpConstraintFree(hookJoint); 59 hookJoint = null; 60 } 61 62 cpSpaceStep(space, dt); 63 } 64 65 enum 66 { 67 HOOK_SENSOR = 1, 68 CRATE, 69 }; 70 71 static void AttachHook(cpSpace* space, cpBody* hook, cpBody* crate) 72 { 73 hookJoint = cpSpaceAddConstraint(space, cpPivotJointNew(hook, crate, cpBodyGetPos(hook))); 74 } 75 76 static cpBool HookCrate(cpArbiter* arb, cpSpace* space, void* data) 77 { 78 if (hookJoint == null) 79 { 80 // Get pointers to the two bodies in the collision pair and define local variables for them. 81 // Their order matches the order of the collision types passed 82 // to the collision handler this function was defined for 83 mixin(CP_ARBITER_GET_BODIES!("arb", "hook", "crate")); 84 85 // additions and removals can't be done in a normal callback. 86 // Schedule a post step callback to do it. 87 // Use the hook as the key and pass along the arbiter. 88 cpSpaceAddPostStepCallback(space, safeCast!cpPostStepFunc(&AttachHook), hook, crate); 89 } 90 91 return cpTrue; // return value is ignored for sensor callbacks anyway 92 } 93 94 static cpSpace* init() 95 { 96 ChipmunkDemoMessageString = "Control the crane by moving the mouse. Right click to release.".dup; 97 98 cpSpace* space = cpSpaceNew(); 99 cpSpaceSetIterations(space, 30); 100 cpSpaceSetGravity(space, cpv(0, -100)); 101 cpSpaceSetDamping(space, 0.8); 102 103 cpBody * staticBody = cpSpaceGetStaticBody(space); 104 cpShape* shape; 105 106 shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320, -240), cpv(320, -240), 0.0f)); 107 cpShapeSetElasticity(shape, 1.0f); 108 cpShapeSetFriction(shape, 1.0f); 109 cpShapeSetLayers(shape, NOT_GRABABLE_MASK); 110 111 // Add a body for the dolly. 112 dollyBody = cpSpaceAddBody(space, cpBodyNew(10, INFINITY)); 113 cpBodySetPos(dollyBody, cpv(0, 100)); 114 115 // Add a block so you can see it. 116 cpSpaceAddShape(space, cpBoxShapeNew(dollyBody, 30, 30)); 117 118 // Add a groove joint for it to move back and forth on. 119 cpSpaceAddConstraint(space, cpGrooveJointNew(staticBody, dollyBody, cpv(-250, 100), cpv(250, 100), cpvzero)); 120 121 // Add a pivot joint to act as a servo motor controlling it's position 122 // By updating the anchor points of the pivot joint, you can move the dolly. 123 dollyServo = cpSpaceAddConstraint(space, cpPivotJointNew(staticBody, dollyBody, cpBodyGetPos(dollyBody))); 124 125 // Max force the dolly servo can generate. 126 cpConstraintSetMaxForce(dollyServo, 10000); 127 128 // Max speed of the dolly servo 129 cpConstraintSetMaxBias(dollyServo, 100); 130 131 // You can also change the error bias to control how it slows down. 132 //cpConstraintSetErrorBias(dollyServo, 0.2); 133 134 // Add the crane hook. 135 cpBody* hookBody = cpSpaceAddBody(space, cpBodyNew(1, INFINITY)); 136 cpBodySetPos(hookBody, cpv(0, 50)); 137 138 // Add a sensor shape for it. This will be used to figure out when the hook touches a box. 139 shape = cpSpaceAddShape(space, cpCircleShapeNew(hookBody, 10, cpvzero)); 140 cpShapeSetSensor(shape, cpTrue); 141 cpShapeSetCollisionType(shape, HOOK_SENSOR); 142 143 // Add a slide joint to act as a winch motor 144 // By updating the max length of the joint you can make it pull up the load. 145 winchServo = cpSpaceAddConstraint(space, cpSlideJointNew(dollyBody, hookBody, cpvzero, cpvzero, 0, INFINITY)); 146 147 // Max force the dolly servo can generate. 148 cpConstraintSetMaxForce(winchServo, 30000); 149 150 // Max speed of the dolly servo 151 cpConstraintSetMaxBias(winchServo, 60); 152 153 // TODO cleanup 154 // Finally a box to play with 155 cpBody* boxBody = cpSpaceAddBody(space, cpBodyNew(30, cpMomentForBox(30, 50, 50))); 156 cpBodySetPos(boxBody, cpv(200, -200)); 157 158 // Add a block so you can see it. 159 shape = cpSpaceAddShape(space, cpBoxShapeNew(boxBody, 50, 50)); 160 cpShapeSetFriction(shape, 0.7); 161 cpShapeSetCollisionType(shape, CRATE); 162 163 cpSpaceAddCollisionHandler(space, HOOK_SENSOR, CRATE, safeCast!cpCollisionBeginFunc(&HookCrate), null, null, null, null); 164 165 return space; 166 } 167 168 static void destroy(cpSpace* space) 169 { 170 ChipmunkDemoFreeSpaceChildren(space); 171 cpSpaceFree(space); 172 } 173 174 ChipmunkDemo Crane = { 175 "Crane", 176 1.0 / 60.0, 177 &init, 178 &update, 179 &ChipmunkDemoDefaultDrawImpl, 180 &destroy, 181 };