1 
2 // written in the D programming language
3 
4 module samples.Sensors;
5 
6 import dchip.all;
7 
8 import samples.ChipmunkDemo;
9 
10 static cpSpace *space;
11 
12 enum CollisionTypes {
13     BALL_TYPE,
14     BLOCKING_SENSOR_TYPE,
15     CATCH_SENSOR_TYPE,
16 };
17 
18 struct Emitter {
19     int queue;
20     int blocked;
21     cpVect position;
22 }
23 
24 static Emitter emitterInstance;
25 
26 static cpBool
27 blockerBegin(cpArbiter *arb, cpSpace *space, void *unused)
28 {
29     mixin(CP_ARBITER_GET_SHAPES!("arb", "a", "b"));
30     Emitter *emitter = cast(Emitter *) a.data;
31 
32     emitter.blocked++;
33 
34     return cpFalse; // Return values from sensors callbacks are ignored,
35 }
36 
37 static void
38 blockerSeparate(cpArbiter *arb, cpSpace *space, void *unused)
39 {
40     mixin(CP_ARBITER_GET_SHAPES!("arb", "a", "b"));
41     Emitter *emitter = cast(Emitter *)a.data;
42 
43     emitter.blocked--;
44 }
45 
46 static void
47 postStepRemove(cpSpace *space, cpShape *shape, void *unused)
48 {
49     cpSpaceRemoveBody(space, shape.body_);
50     cpSpaceRemoveShape(space, shape);
51 
52     cpBodyFree(shape.body_);
53     cpShapeFree(shape);
54 }
55 
56 static cpBool
57 catcherBarBegin(cpArbiter *arb, cpSpace *space, void *unused)
58 {
59     mixin(CP_ARBITER_GET_SHAPES!("arb", "a", "b"));
60     Emitter *emitter = cast(Emitter *) a.data;
61 
62     emitter.queue++;
63     cpSpaceAddPostStepCallback(space, cast(cpPostStepFunc)&postStepRemove, b, null);
64 
65     return cpFalse;
66 }
67 
68 static cpFloat frand_unit(){return 2.0f*(frand()) - 1.0f;}
69 
70 static void
71 update(int ticks)
72 {
73     int steps = 1;
74     cpFloat dt = 1.0f/60.0f/cast(cpFloat)steps;
75 
76     if(!emitterInstance.blocked && emitterInstance.queue){
77         emitterInstance.queue--;
78 
79         cpBody *body_ = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForCircle(1.0f, 15.0f, 0.0f, cpvzero)));
80         body_.p = emitterInstance.position;
81         body_.v = cpvmult(cpv(frand_unit(), frand_unit()), 100.0f);
82 
83         cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(body_, 15.0f, cpvzero));
84         shape.collision_type = CollisionTypes.BALL_TYPE;
85     }
86 
87     for(int i=0; i<steps; i++){
88         cpSpaceStep(space, dt);
89     }
90 }
91 
92 static cpSpace *
93 init()
94 {
95     cpResetShapeIdCounter();
96 
97     space = cpSpaceNew();
98     space.iterations = 10;
99     space.gravity = cpv(0, -100);
100 
101     cpBody *staticBody = space.staticBody;
102     cpShape *shape;
103 
104     // Data structure for our ball emitter
105     // We'll use two sensors for it, one to see if the emitter is blocked
106     // a second to catch the balls and add them back to the emitter
107     emitterInstance.queue = 5;
108     emitterInstance.blocked = 0;
109     emitterInstance.position = cpv(0, 150);
110 
111     // Create our blocking sensor, so we know when the emitter is clear to emit another ball
112     shape = cpSpaceAddShape(space, cpCircleShapeNew(staticBody, 15.0f, emitterInstance.position));
113     shape.sensor = 1;
114     shape.collision_type = CollisionTypes.BLOCKING_SENSOR_TYPE;
115     shape.data = &emitterInstance;
116 
117     // Create our catch sensor to requeue the balls when they reach the bottom of the screen
118     shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-2000, -200), cpv(2000, -200), 15.0f));
119     shape.sensor = 1;
120     shape.collision_type = CollisionTypes.CATCH_SENSOR_TYPE;
121     shape.data = &emitterInstance;
122 
123     cpSpaceAddCollisionHandler(space, CollisionTypes.BLOCKING_SENSOR_TYPE, CollisionTypes.BALL_TYPE, &blockerBegin, null, null, &blockerSeparate, null);
124     cpSpaceAddCollisionHandler(space, CollisionTypes.CATCH_SENSOR_TYPE, CollisionTypes.BALL_TYPE, &catcherBarBegin, null, null, null, null);
125 
126     return space;
127 }
128 
129 static void
130 destroy()
131 {
132     ChipmunkDemoFreeSpaceChildren(space);
133     cpSpaceFree(space);
134 }
135 
136 chipmunkDemo Sensors = {
137     "Sensors",
138     null,
139     &init,
140     &update,
141     &destroy,
142 };