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 };