/* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk/chipmunk.h" #include "ChipmunkDemo.h" #define CHAIN_COUNT 8 #define LINK_COUNT 10 static void BreakablejointPostStepRemove(cpSpace* space, cpConstraint* joint, void* unused) { cpSpaceRemoveConstraint(space, joint); cpConstraintFree(joint); } static void BreakableJointPostSolve(cpConstraint* joint, cpSpace* space) { cpFloat dt = cpSpaceGetCurrentTimeStep(space); // Convert the impulse to a force by dividing it by the timestep. cpFloat force = cpConstraintGetImpulse(joint) / dt; cpFloat maxForce = cpConstraintGetMaxForce(joint); // If the force is almost as big as the joint's max force, break it. if (force > 0.9 * maxForce) { cpSpaceAddPostStepCallback(space, (cpPostStepFunc)BreakablejointPostStepRemove, joint, NULL); } } static void update(cpSpace* space, double dt) { cpSpaceStep(space, dt); } static cpSpace* init(void) { cpSpace* space = cpSpaceNew(); cpSpaceSetIterations(space, 30); cpSpaceSetGravity(space, cpv(0, -100)); cpSpaceSetSleepTimeThreshold(space, 0.5f); cpBody *body, *staticBody = cpSpaceGetStaticBody(space); cpShape* shape; // Create segments around the edge of the screen. shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320, -240), cpv(-320, 240), 0.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetFilter(shape, NOT_GRABBABLE_FILTER); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(320, -240), cpv(320, 240), 0.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetFilter(shape, NOT_GRABBABLE_FILTER); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320, -240), cpv(320, -240), 0.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetFilter(shape, NOT_GRABBABLE_FILTER); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320, 240), cpv(320, 240), 0.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetFilter(shape, NOT_GRABBABLE_FILTER); cpFloat mass = 1; cpFloat width = 20; cpFloat height = 30; cpFloat spacing = width * 0.3; // Add lots of boxes. for (int i = 0; i < CHAIN_COUNT; i++) { cpBody* prev = NULL; for (int j = 0; j < LINK_COUNT; j++) { cpVect pos = cpv(40 * (i - (CHAIN_COUNT - 1) / 2.0), 240 - (j + 0.5) * height - (j + 1) * spacing); body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForBox(mass, width, height))); cpBodySetPosition(body, pos); shape = cpSpaceAddShape(space, cpSegmentShapeNew(body, cpv(0, (height - width) / 2.0), cpv(0, (width - height) / 2.0), width / 2.0)); cpShapeSetFriction(shape, 0.8f); cpFloat breakingForce = 80000; cpConstraint* constraint = NULL; if (prev == NULL) { constraint = cpSpaceAddConstraint( space, cpSlideJointNew(body, staticBody, cpv(0, height / 2), cpv(pos.x, 240), 0, spacing)); } else { constraint = cpSpaceAddConstraint( space, cpSlideJointNew(body, prev, cpv(0, height / 2), cpv(0, -height / 2), 0, spacing)); } cpConstraintSetMaxForce(constraint, breakingForce); cpConstraintSetPostSolveFunc(constraint, BreakableJointPostSolve); cpConstraintSetCollideBodies(constraint, cpFalse); prev = body; } } cpFloat radius = 15.0f; body = cpSpaceAddBody(space, cpBodyNew(10.0f, cpMomentForCircle(10.0f, 0.0f, radius, cpvzero))); cpBodySetPosition(body, cpv(0, -240 + radius + 5)); cpBodySetVelocity(body, cpv(0, 300)); shape = cpSpaceAddShape(space, cpCircleShapeNew(body, radius, cpvzero)); cpShapeSetElasticity(shape, 0.0f); cpShapeSetFriction(shape, 0.9f); return space; } static void destroy(cpSpace* space) { ChipmunkDemoFreeSpaceChildren(space); cpSpaceFree(space); } ChipmunkDemo Chains = { "Breakable Chains", 1.0 / 180.0, init, update, ChipmunkDemoDefaultDrawImpl, destroy, };