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.Tumble;
23 
24 import core.stdc.stdlib;
25 
26 import demo.dchip;
27 
28 import demo.ChipmunkDebugDraw;
29 import demo.ChipmunkDemo;
30 import demo.types;
31 
32 cpBody* rogueBoxBody;
33 
34 void update(cpSpace* space, double dt)
35 {
36     // Manually update the position of the box body_ so that the box rotates.
37     // Normally Chipmunk calls this and cpBodyUpdateVelocity() for you,
38     // but we wanted to control the angular velocity explicitly.
39     cpBodyUpdatePosition(rogueBoxBody, dt);
40 
41     cpSpaceStep(space, dt);
42 }
43 
44 void AddBox(cpSpace* space, cpVect pos, cpFloat mass, cpFloat width, cpFloat height)
45 {
46     cpBody* body_ = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForBox(mass, width, height)));
47     cpBodySetPos(body_, pos);
48 
49     cpShape* shape = cpSpaceAddShape(space, cpBoxShapeNew(body_, width, height));
50     cpShapeSetElasticity(shape, 0.0f);
51     cpShapeSetFriction(shape, 0.7f);
52 }
53 
54 void AddSegment(cpSpace* space, cpVect pos, cpFloat mass, cpFloat width, cpFloat height)
55 {
56     cpBody* body_ = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForBox(mass, width, height)));
57     cpBodySetPos(body_, pos);
58 
59     cpShape* shape = cpSpaceAddShape(space, cpSegmentShapeNew(body_, cpv(0.0, (height - width) / 2.0), cpv(0.0, (width - height) / 2.0), width / 2.0));
60     cpShapeSetElasticity(shape, 0.0f);
61     cpShapeSetFriction(shape, 0.7f);
62 }
63 
64 void AddCircle(cpSpace* space, cpVect pos, cpFloat mass, cpFloat radius)
65 {
66     cpBody* body_ = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForCircle(mass, 0.0, radius, cpvzero)));
67     cpBodySetPos(body_, pos);
68 
69     cpShape* shape = cpSpaceAddShape(space, cpCircleShapeNew(body_, radius, cpvzero));
70     cpShapeSetElasticity(shape, 0.0f);
71     cpShapeSetFriction(shape, 0.7f);
72 }
73 
74 cpSpace* init()
75 {
76     cpSpace* space = cpSpaceNew();
77     cpSpaceSetGravity(space, cpv(0, -600));
78 
79     cpShape* shape;
80 
81     // We create an infinite mass rogue body_ to attach the line segments too
82     // This way we can control the rotation however we want.
83     rogueBoxBody = cpBodyNew(INFINITY, INFINITY);
84     cpBodySetAngVel(rogueBoxBody, 0.4f);
85 
86     // Set up the static box.
87     cpVect a = cpv(-200, -200);
88     cpVect b = cpv(-200, 200);
89     cpVect c = cpv(200, 200);
90     cpVect d = cpv(200, -200);
91 
92     shape = cpSpaceAddShape(space, cpSegmentShapeNew(rogueBoxBody, a, b, 0.0f));
93     cpShapeSetElasticity(shape, 1.0f);
94     cpShapeSetFriction(shape, 1.0f);
95     cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
96 
97     shape = cpSpaceAddShape(space, cpSegmentShapeNew(rogueBoxBody, b, c, 0.0f));
98     cpShapeSetElasticity(shape, 1.0f);
99     cpShapeSetFriction(shape, 1.0f);
100     cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
101 
102     shape = cpSpaceAddShape(space, cpSegmentShapeNew(rogueBoxBody, c, d, 0.0f));
103     cpShapeSetElasticity(shape, 1.0f);
104     cpShapeSetFriction(shape, 1.0f);
105     cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
106 
107     shape = cpSpaceAddShape(space, cpSegmentShapeNew(rogueBoxBody, d, a, 0.0f));
108     cpShapeSetElasticity(shape, 1.0f);
109     cpShapeSetFriction(shape, 1.0f);
110     cpShapeSetLayers(shape, NOT_GRABABLE_MASK);
111 
112     cpFloat mass   = 1;
113     cpFloat width  = 30;
114     cpFloat height = width * 2;
115 
116     // Add the bricks.
117     for (int i = 0; i < 7; i++)
118     {
119         for (int j = 0; j < 3; j++)
120         {
121             cpVect pos = cpv(i * width - 150, j * height - 150);
122 
123             int type = (rand() % 3000) / 1000;
124 
125             if (type == 0)
126             {
127                 AddBox(space, pos, mass, width, height);
128             }
129             else if (type == 1)
130             {
131                 AddSegment(space, pos, mass, width, height);
132             }
133             else
134             {
135                 AddCircle(space, cpvadd(pos, cpv(0.0, (height - width) / 2.0)), mass, width / 2.0);
136                 AddCircle(space, cpvadd(pos, cpv(0.0, (width - height) / 2.0)), mass, width / 2.0);
137             }
138         }
139     }
140 
141     return space;
142 }
143 
144 void destroy(cpSpace* space)
145 {
146     ChipmunkDemoFreeSpaceChildren(space);
147     cpBodyFree(rogueBoxBody);
148     cpSpaceFree(space);
149 }
150 
151 ChipmunkDemo Tumble = {
152     "Tumble",
153     1.0 / 180.0,
154     &init,
155     &update,
156     &ChipmunkDemoDefaultDrawImpl,
157     &destroy,
158 };