1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include "asset_cache.h"
#include "collision.h"
#include "forces.h"
#include "sdl_wrapper.h"
const double BALL_RADIUS = 15;
const double BALL_MASS = 5;
const vector_t BALL_INIT_VEL = {400, 400};
const vector_t BALL_INIT_POS = {500, 70};
const double ELASTICITY = 1;
const double RECTANGLE_WIDTH = 98;
const double RECTANGLE_HEIGHT = 40;
const vector_t MIN = {0, 0};
const vector_t MAX = {1000, 500};
const double resting_speed = 300;
const double ACCEL = 100;
const size_t BRICKS_IN_ROW = 10;
const size_t ROWS = 3;
const double BRICK_INIT_Y = 475;
const double BRICK_OFFSET = 3;
const double WALL_DIM = 1;
const double USER_HEIGHT = 25;
const vector_t USER_INIT_POS = {500, 25};
rgb_color_t user_color = (rgb_color_t){0.5, 0.5, 0.5};
rgb_color_t white = (rgb_color_t){1, 1, 1};
vector_t FIRST_STONE = {1, 7};
vector_t SECOND_STONE = {2, 2};
const size_t CIRC_NPOINTS = 100;
struct state {
scene_t *scene;
double time_pressed;
body_t *ball;
body_t *user;
};
typedef enum { BALL, WALL, BRICK, GROUND } body_type_t;
body_type_t *make_type_info(body_type_t type) {
body_type_t *info = malloc(sizeof(body_type_t));
*info = type;
return info;
}
body_type_t get_type(body_t *body) {
return *(body_type_t *)body_get_info(body);
}
/** Make a circle-shaped body object.
*
* @param center a vector representing the center of the body.
* @param radius the radius of the circle
* @param mass the mass of the body
* @param color the color of the circle
* @return pointer to the circle-shaped body
*/
list_t *make_circle(vector_t center, double radius) {
list_t *c = list_init(CIRC_NPOINTS, free);
for (size_t i = 0; i < CIRC_NPOINTS; i++) {
double angle = 2 * M_PI * i / CIRC_NPOINTS;
vector_t *v = malloc(sizeof(*v));
*v = (vector_t){center.x + radius * cos(angle),
center.y + radius * sin(angle)};
list_add(c, v);
}
return c;
}
/** Make a rectangle-shaped body object.
*
* @param center a vector representing the center of the body.
* @param width the width of the rectangle
* @param height the height of the rectangle
* @return pointer to the rectangle-shaped body
*/
list_t *make_rectangle(vector_t center, double width, double height) {
list_t *points = list_init(4, free);
vector_t *p1 = malloc(sizeof(vector_t));
*p1 = (vector_t){center.x - width / 2, center.y - height / 2};
vector_t *p2 = malloc(sizeof(vector_t));
*p2 = (vector_t){center.x + width / 2, center.y - height / 2};
vector_t *p3 = malloc(sizeof(vector_t));
*p3 = (vector_t){center.x + width / 2, center.y + height / 2};
vector_t *p4 = malloc(sizeof(vector_t));
*p4 = (vector_t){center.x - width / 2, center.y + height / 2};
list_add(points, p1);
list_add(points, p2);
list_add(points, p3);
list_add(points, p4);
return points;
}
/**
* Wrap object around other side of screen display if it reaches any edge of the
* display.
*
* @param body the body object representing pacman
*/
void user_wrap_edges(body_t *body) {
vector_t centroid = body_get_centroid(body);
if (centroid.x - RECTANGLE_WIDTH / 2 > MAX.x) {
body_set_centroid(body, (vector_t){MIN.x, centroid.y});
} else if (centroid.x + RECTANGLE_WIDTH / 2 < MIN.x) {
body_set_centroid(body, (vector_t){MAX.x, centroid.y});
}
}
/**
* Move player on display screen based on key pressed.
*
* @param key the character of the key pressed
* @param type event type connected to key
* @param held_time double value representing the amount of time the key is held
* down
* @param state the state representing the current demo
*/
void on_key(char key, key_event_type_t type, double held_time, state_t *state) {
// TODO: implement this!
}
/**
* Create a list of colors for the rainbow bricks in breakout demo.
*
* @return a pointer to a list containing the colors of the bricks.
*/
list_t *get_colors() {
list_t *color = list_init(BRICKS_IN_ROW, free);
for (double i = 0; i < 1; i += (1. / BRICKS_IN_ROW)) {
list_add(color, color_init(i, 0.7, 0.7));
}
return color;
}
/**
* Adds bricks as bodies to the scene.
*
* @param state the current state of the demo
*/
void add_bricks(state_t *state) {
list_t *colors = get_colors();
double rect_width = MAX.x / BRICKS_IN_ROW;
for (int j = 0; j < BRICKS_IN_ROW; j++) {
double x = rect_width / 2 + j * (rect_width + BRICK_OFFSET);
for (int i = 0; i < ROWS; i++) {
double y = BRICK_INIT_Y - i * (RECTANGLE_HEIGHT + BRICK_OFFSET);
list_t *rect =
make_rectangle((vector_t){x, y}, rect_width, RECTANGLE_HEIGHT);
body_t *box;
// add stones that cannot be destroyed
if ((i == FIRST_STONE.x && j == FIRST_STONE.y) ||
(i == SECOND_STONE.x && j == SECOND_STONE.y)) {
rgb_color_t color = user_color;
box = body_init_with_info(rect, INFINITY, color, make_type_info(WALL),
free);
}
// add bricks that can be destroyed
else {
rgb_color_t color = *((rgb_color_t *)(list_get(colors, j)));
box = body_init_with_info(rect, INFINITY, color, make_type_info(BRICK),
free);
}
scene_add_body(state->scene, box);
}
}
list_free(colors);
}
/**
* Adds walls as bodies to the scene.
*
* @param state the current state of the demo
*/
void add_walls(state_t *state) {
list_t *wall1_shape =
make_rectangle((vector_t){MAX.x, MAX.y / 2}, WALL_DIM, MAX.y);
body_t *wall1 = body_init_with_info(wall1_shape, INFINITY, white,
make_type_info(WALL), free);
list_t *wall2_shape =
make_rectangle((vector_t){0, MAX.y / 2}, WALL_DIM, MAX.y);
body_t *wall2 = body_init_with_info(wall2_shape, INFINITY, white,
make_type_info(WALL), free);
list_t *ceiling_shape =
make_rectangle((vector_t){MAX.x / 2, MAX.y}, MAX.x, WALL_DIM);
body_t *ceiling = body_init_with_info(ceiling_shape, INFINITY, white,
make_type_info(WALL), free);
list_t *ground_shape =
make_rectangle((vector_t){MAX.x / 2, 0}, MAX.x, WALL_DIM);
body_t *ground = body_init_with_info(ground_shape, INFINITY, white,
make_type_info(GROUND), free);
scene_add_body(state->scene, wall1);
scene_add_body(state->scene, wall2);
scene_add_body(state->scene, ceiling);
scene_add_body(state->scene, ground);
}
/**
* Adds a ball as a body to the scene.
*
* @param state the current state of the demo
*/
void add_ball(state_t *state) {
list_t *ball_shape = make_circle(BALL_INIT_POS, BALL_RADIUS);
// TODO: implement this!
}
/**
* Adds the user as a body to the scene.
*
* @param state the current state of the demo
*/
void add_user(state_t *state) {
list_t *user_shape =
make_rectangle(USER_INIT_POS, RECTANGLE_WIDTH, USER_HEIGHT);
// TODO: implement this!
}
/**
* The collision handler for collisions between the ball and the brick.
*
* @param body1 the body for the ball
* @param body2 the body for the brick
* @param axis the axis of collision
* @param aux the aux passed in from `create_breakout_collision`
* @param elasticity the elasticity of the collision between the ball and the
* brick
*/
void breakout_collision_handler(body_t *body1, body_t *body2, vector_t axis,
void *aux, double force_const) {
// TODO: fill this in!
}
/**
* The breakout collision creator for `breakout_collision_handler`.
*
* @param scene the scene of the game
* @param body1 the body for the ball
* @param body2 the body for the brick
* @param elasticity the elasticity of the collision between the ball and the
* brick
*/
void create_breakout_collision(scene_t *scene, body_t *body1, body_t *body2,
double elasticity) {
// TODO: fill this in!
}
/**
* Reset the game to initial starting positions/velocities.
* This function is a collision handler.
*
* @param body1 pointer to a body involved in collision
* @param body2 pointer to a body involved in collision
* @param axis the axis of collision
* @param aux auxiliary information for the collision (in this case it is a
* pointer to a state_t)
*/
void reset_game(body_t *body1, body_t *body2, vector_t axis, void *aux,
double force_const) {
// When reset_game was "registered" as a collision handler, the game state
// should have been passed in as the aux. This gives us access to the
// state after the collision between the ball and the ground, allowing us
// to reset the game.
state_t *state = aux;
// TODO: clear and re-add bricks. Which function initializes bricks in the
// beginning of the game?
// TODO: reset ball's velocity and position
// TODO: reset ball's forces and impulses
// TODO: re-add force creators for bricks
}
/**
* Adds collision handler force creators between appropriate bodies.
*
* @param state the current state of the demo
*/
void add_force_creators(state_t *state) {
for (size_t i = 0; i < scene_bodies(state->scene); i++) {
body_t *body = scene_get_body(state->scene, i);
switch (get_type(body)) {
case BRICK:
// TODO: register the collision handler that should run when the ball and
// the brick collides
break;
case WALL:
// TODO: register the collision handler that should run when the ball and
// the wall collides
break;
case GROUND:
// TODO: register the collision handler that should run when the ball and
// the ground collides
break;
default:
break;
}
}
}
state_t *emscripten_init() {
// TODO: implement this!
}
bool emscripten_main(state_t *state) {
// TODO: implement this!
}
void emscripten_free(state_t *state) {
// TODO: implement this!
}