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.Chains; 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 enum CHAIN_COUNT = 8; 37 enum LINK_COUNT = 10; 38 39 static void BreakablejointPostStepRemove(cpSpace* space, cpConstraint* joint, void* unused) 40 { 41 cpSpaceRemoveConstraint(space, joint); 42 cpConstraintFree(joint); 43 } 44 45 static void BreakableJointPostSolve(cpConstraint* joint, cpSpace* space) 46 { 47 cpFloat dt = cpSpaceGetCurrentTimeStep(space); 48 49 // Convert the impulse to a force by dividing it by the timestep. 50 cpFloat force = cpConstraintGetImpulse(joint) / dt; 51 cpFloat maxForce = cpConstraintGetMaxForce(joint); 52 53 // If the force is almost as big as the joint's max force, break it. 54 if (force > 0.9 * maxForce) 55 { 56 cpSpaceAddPostStepCallback(space, safeCast!cpPostStepFunc(&BreakablejointPostStepRemove), joint, null); 57 } 58 } 59 60 static void update(cpSpace* space, double dt) 61 { 62 cpSpaceStep(space, dt); 63 } 64 65 static cpSpace* init() 66 { 67 cpSpace* space = cpSpaceNew(); 68 cpSpaceSetIterations(space, 30); 69 cpSpaceSetGravity(space, cpv(0, -100)); 70 cpSpaceSetSleepTimeThreshold(space, 0.5f); 71 72 cpBody * body_; 73 cpBody * staticBody = cpSpaceGetStaticBody(space); 74 cpShape* shape; 75 76 // Create segments around the edge of the screen. 77 shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320, -240), cpv(-320, 240), 0.0f)); 78 cpShapeSetElasticity(shape, 1.0f); 79 cpShapeSetFriction(shape, 1.0f); 80 cpShapeSetLayers(shape, NOT_GRABABLE_MASK); 81 82 shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(320, -240), cpv(320, 240), 0.0f)); 83 cpShapeSetElasticity(shape, 1.0f); 84 cpShapeSetFriction(shape, 1.0f); 85 cpShapeSetLayers(shape, NOT_GRABABLE_MASK); 86 87 shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320, -240), cpv(320, -240), 0.0f)); 88 cpShapeSetElasticity(shape, 1.0f); 89 cpShapeSetFriction(shape, 1.0f); 90 cpShapeSetLayers(shape, NOT_GRABABLE_MASK); 91 92 shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320, 240), cpv(320, 240), 0.0f)); 93 cpShapeSetElasticity(shape, 1.0f); 94 cpShapeSetFriction(shape, 1.0f); 95 cpShapeSetLayers(shape, NOT_GRABABLE_MASK); 96 97 cpFloat mass = 1; 98 cpFloat width = 20; 99 cpFloat height = 30; 100 101 cpFloat spacing = width * 0.3; 102 103 // Add lots of boxes. 104 for (int i = 0; i < CHAIN_COUNT; i++) 105 { 106 cpBody* prev = null; 107 108 for (int j = 0; j < LINK_COUNT; j++) 109 { 110 cpVect pos = cpv(40 * (i - (CHAIN_COUNT - 1) / 2.0), 240 - (j + 0.5) * height - (j + 1) * spacing); 111 112 body_ = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForBox(mass, width, height))); 113 cpBodySetPos(body_, pos); 114 115 shape = cpSpaceAddShape(space, cpSegmentShapeNew(body_, cpv(0, (height - width) / 2.0), cpv(0, (width - height) / 2.0), width / 2.0)); 116 cpShapeSetFriction(shape, 0.8f); 117 118 cpFloat breakingForce = 80000; 119 120 cpConstraint* constraint = null; 121 122 if (prev == null) 123 { 124 constraint = cpSpaceAddConstraint(space, cpSlideJointNew(body_, staticBody, cpv(0, height / 2), cpv(pos.x, 240), 0, spacing)); 125 } 126 else 127 { 128 constraint = cpSpaceAddConstraint(space, cpSlideJointNew(body_, prev, cpv(0, height / 2), cpv(0, -height / 2), 0, spacing)); 129 } 130 131 cpConstraintSetMaxForce(constraint, breakingForce); 132 cpConstraintSetPostSolveFunc(constraint, &BreakableJointPostSolve); 133 134 prev = body_; 135 } 136 } 137 138 cpFloat radius = 15.0f; 139 body_ = cpSpaceAddBody(space, cpBodyNew(10.0f, cpMomentForCircle(10.0f, 0.0f, radius, cpvzero))); 140 cpBodySetPos(body_, cpv(0, -240 + radius + 5)); 141 cpBodySetVel(body_, cpv(0, 300)); 142 143 shape = cpSpaceAddShape(space, cpCircleShapeNew(body_, radius, cpvzero)); 144 cpShapeSetElasticity(shape, 0.0f); 145 cpShapeSetFriction(shape, 0.9f); 146 147 return space; 148 } 149 150 static void destroy(cpSpace* space) 151 { 152 ChipmunkDemoFreeSpaceChildren(space); 153 cpSpaceFree(space); 154 } 155 156 ChipmunkDemo Chains = { 157 "Breakable Chains", 158 1.0 / 180.0, 159 &init, 160 &update, 161 &ChipmunkDemoDefaultDrawImpl, 162 &destroy, 163 };