1 
2 // written in the D programming language
3 
4 module samples.Planet;
5 
6 import dchip.all;
7 
8 import samples.ChipmunkDemo;
9 
10 static cpSpace *space;
11 static cpBody *planetBody;
12 
13 static cpFloat gravityStrength = 5.0e6f;
14 
15 static void
16 update(int ticks)
17 {
18     int steps = 1;
19     cpFloat dt = 1.0f/60.0f/cast(cpFloat)steps;
20 
21     for(int i=0; i<steps; i++){
22         cpSpaceStep(space, dt);
23 
24         // Update the static body spin so that it looks like it's rotating.
25         cpBodyUpdatePosition(planetBody, dt);
26     }
27 }
28 
29 static void
30 planetGravityVelocityFunc(cpBody *_body, cpVect gravity, cpFloat damping, cpFloat dt)
31 {
32     // Gravitational acceleration is proportional to the inverse square of
33     // distance, and directed toward the origin. The central planet is assumed
34     // to be massive enough that it affects the satellites but not vice versa.
35     cpVect p = _body.p;
36     cpFloat sqdist = cpvlengthsq(p);
37     cpVect g = cpvmult(p, -gravityStrength / (sqdist * cpfsqrt(sqdist)));
38 
39     cpBodyUpdateVelocity(_body, g, damping, dt);
40 }
41 
42 static cpVect
43 rand_pos(cpFloat radius)
44 {
45     cpVect v;
46     do {
47         v = cpv(frand()*(640 - 2*radius) - (320 - radius), frand()*(480 - 2*radius) - (240 - radius));
48     } while(cpvlength(v) < 85.0f);
49 
50     return v;
51 }
52 
53 static void
54 add_box()
55 {
56     const cpFloat size = 10.0f;
57     const cpFloat mass = 1.0f;
58 
59     cpVect verts[] = [
60         cpv(-size,-size),
61         cpv(-size, size),
62         cpv( size, size),
63         cpv( size,-size),
64     ];
65 
66     cpFloat radius = cpvlength(cpv(size, size));
67 
68     cpBody *_body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForPoly(mass, 4, verts.ptr, cpvzero)));
69     _body.velocity_func = &planetGravityVelocityFunc;
70     _body.p = rand_pos(radius);
71 
72     // Set the box's velocity to put it into a circular orbit from its
73     // starting position.
74     cpFloat r = cpvlength(_body.p);
75     cpFloat v = cpfsqrt(gravityStrength / r) / r;
76     _body.v = cpvmult(cpvperp(_body.p), v);
77 
78     // Set the box's angular velocity to match its orbital period and
79     // align its initial angle with its position.
80     _body.w = v;
81     cpBodySetAngle(_body, cpfatan2(_body.p.y, _body.p.x));
82 
83     cpShape *shape = cpSpaceAddShape(space, cpPolyShapeNew(_body, 4, verts.ptr, cpvzero));
84     shape.e = 0.0f; shape.u = 0.7f;
85 }
86 
87 static cpSpace *
88 init()
89 {
90     planetBody = cpBodyNew(INFINITY, INFINITY);
91     planetBody.w = 0.2f;
92 
93     cpResetShapeIdCounter();
94 
95     space = cpSpaceNew();
96     space.iterations = 20;
97 
98     for(int i=0; i<30; i++)
99         add_box();
100 
101     cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(planetBody, 70.0f, cpvzero));
102     shape.e = 1.0f; shape.u = 1.0f;
103     shape.layers = NOT_GRABABLE_MASK;
104 
105     return space;
106 }
107 
108 static void
109 destroy()
110 {
111     cpBodyFree(planetBody);
112     ChipmunkDemoFreeSpaceChildren(space);
113     cpSpaceFree(space);
114 }
115 
116 chipmunkDemo Planet = {
117     "Planet",
118     null,
119     &init,
120     &update,
121     &destroy,
122 };