1 | /******************************************************************************************* |
2 | * |
3 | * raylib - sample game: space invaders |
4 | * |
5 | * Sample game developed by Ian Eito, Albert Martos and Ramon Santamaria |
6 | * |
7 | * This game has been created using raylib v1.3 (www.raylib.com) |
8 | * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) |
9 | * |
10 | * Copyright (c) 2015 Ramon Santamaria (@raysan5) |
11 | * |
12 | ********************************************************************************************/ |
13 | |
14 | #include "raylib.h" |
15 | |
16 | #if defined(PLATFORM_WEB) |
17 | #include <emscripten/emscripten.h> |
18 | #endif |
19 | |
20 | //---------------------------------------------------------------------------------- |
21 | // Some Defines |
22 | //---------------------------------------------------------------------------------- |
23 | #define NUM_SHOOTS 50 |
24 | #define NUM_MAX_ENEMIES 50 |
25 | #define FIRST_WAVE 10 |
26 | #define SECOND_WAVE 20 |
27 | #define THIRD_WAVE 50 |
28 | |
29 | //---------------------------------------------------------------------------------- |
30 | // Types and Structures Definition |
31 | //---------------------------------------------------------------------------------- |
32 | typedef enum { FIRST = 0, SECOND, THIRD } EnemyWave; |
33 | |
34 | typedef struct Player{ |
35 | Rectangle rec; |
36 | Vector2 speed; |
37 | Color color; |
38 | } Player; |
39 | |
40 | typedef struct Enemy{ |
41 | Rectangle rec; |
42 | Vector2 speed; |
43 | bool active; |
44 | Color color; |
45 | } Enemy; |
46 | |
47 | typedef struct Shoot{ |
48 | Rectangle rec; |
49 | Vector2 speed; |
50 | bool active; |
51 | Color color; |
52 | } Shoot; |
53 | |
54 | //------------------------------------------------------------------------------------ |
55 | // Global Variables Declaration |
56 | //------------------------------------------------------------------------------------ |
57 | static const int screenWidth = 800; |
58 | static const int screenHeight = 450; |
59 | |
60 | static bool gameOver = false; |
61 | static bool pause = false; |
62 | static int score = 0; |
63 | static bool victory = false; |
64 | |
65 | static Player player = { 0 }; |
66 | static Enemy enemy[NUM_MAX_ENEMIES] = { 0 }; |
67 | static Shoot shoot[NUM_SHOOTS] = { 0 }; |
68 | static EnemyWave wave = { 0 }; |
69 | |
70 | static int shootRate = 0; |
71 | static float alpha = 0.0f; |
72 | |
73 | static int activeEnemies = 0; |
74 | static int enemiesKill = 0; |
75 | static bool smooth = false; |
76 | |
77 | //------------------------------------------------------------------------------------ |
78 | // Module Functions Declaration (local) |
79 | //------------------------------------------------------------------------------------ |
80 | static void InitGame(void); // Initialize game |
81 | static void UpdateGame(void); // Update game (one frame) |
82 | static void DrawGame(void); // Draw game (one frame) |
83 | static void UnloadGame(void); // Unload game |
84 | static void UpdateDrawFrame(void); // Update and Draw (one frame) |
85 | |
86 | //------------------------------------------------------------------------------------ |
87 | // Program main entry point |
88 | //------------------------------------------------------------------------------------ |
89 | int main(void) |
90 | { |
91 | // Initialization (Note windowTitle is unused on Android) |
92 | //--------------------------------------------------------- |
93 | InitWindow(screenWidth, screenHeight, "sample game: space invaders" ); |
94 | |
95 | InitGame(); |
96 | |
97 | #if defined(PLATFORM_WEB) |
98 | emscripten_set_main_loop(UpdateDrawFrame, 0, 1); |
99 | #else |
100 | SetTargetFPS(60); |
101 | //-------------------------------------------------------------------------------------- |
102 | |
103 | // Main game loop |
104 | while (!WindowShouldClose()) // Detect window close button or ESC key |
105 | { |
106 | // Update and Draw |
107 | //---------------------------------------------------------------------------------- |
108 | UpdateDrawFrame(); |
109 | //---------------------------------------------------------------------------------- |
110 | } |
111 | #endif |
112 | // De-Initialization |
113 | //-------------------------------------------------------------------------------------- |
114 | UnloadGame(); // Unload loaded data (textures, sounds, models...) |
115 | |
116 | CloseWindow(); // Close window and OpenGL context |
117 | //-------------------------------------------------------------------------------------- |
118 | |
119 | return 0; |
120 | } |
121 | |
122 | //------------------------------------------------------------------------------------ |
123 | // Module Functions Definitions (local) |
124 | //------------------------------------------------------------------------------------ |
125 | |
126 | // Initialize game variables |
127 | void InitGame(void) |
128 | { |
129 | // Initialize game variables |
130 | shootRate = 0; |
131 | pause = false; |
132 | gameOver = false; |
133 | victory = false; |
134 | smooth = false; |
135 | wave = FIRST; |
136 | activeEnemies = FIRST_WAVE; |
137 | enemiesKill = 0; |
138 | score = 0; |
139 | alpha = 0; |
140 | |
141 | // Initialize player |
142 | player.rec.x = 20; |
143 | player.rec.y = 50; |
144 | player.rec.width = 20; |
145 | player.rec.height = 20; |
146 | player.speed.x = 5; |
147 | player.speed.y = 5; |
148 | player.color = BLACK; |
149 | |
150 | // Initialize enemies |
151 | for (int i = 0; i < NUM_MAX_ENEMIES; i++) |
152 | { |
153 | enemy[i].rec.width = 10; |
154 | enemy[i].rec.height = 10; |
155 | enemy[i].rec.x = GetRandomValue(screenWidth, screenWidth + 1000); |
156 | enemy[i].rec.y = GetRandomValue(0, screenHeight - enemy[i].rec.height); |
157 | enemy[i].speed.x = 5; |
158 | enemy[i].speed.y = 5; |
159 | enemy[i].active = true; |
160 | enemy[i].color = GRAY; |
161 | } |
162 | |
163 | // Initialize shoots |
164 | for (int i = 0; i < NUM_SHOOTS; i++) |
165 | { |
166 | shoot[i].rec.x = player.rec.x; |
167 | shoot[i].rec.y = player.rec.y + player.rec.height/4; |
168 | shoot[i].rec.width = 10; |
169 | shoot[i].rec.height = 5; |
170 | shoot[i].speed.x = 7; |
171 | shoot[i].speed.y = 0; |
172 | shoot[i].active = false; |
173 | shoot[i].color = MAROON; |
174 | } |
175 | } |
176 | |
177 | // Update game (one frame) |
178 | void UpdateGame(void) |
179 | { |
180 | if (!gameOver) |
181 | { |
182 | if (IsKeyPressed('P')) pause = !pause; |
183 | |
184 | if (!pause) |
185 | { |
186 | switch (wave) |
187 | { |
188 | case FIRST: |
189 | { |
190 | if (!smooth) |
191 | { |
192 | alpha += 0.02f; |
193 | |
194 | if (alpha >= 1.0f) smooth = true; |
195 | } |
196 | |
197 | if (smooth) alpha -= 0.02f; |
198 | |
199 | if (enemiesKill == activeEnemies) |
200 | { |
201 | enemiesKill = 0; |
202 | |
203 | for (int i = 0; i < activeEnemies; i++) |
204 | { |
205 | if (!enemy[i].active) enemy[i].active = true; |
206 | } |
207 | |
208 | activeEnemies = SECOND_WAVE; |
209 | wave = SECOND; |
210 | smooth = false; |
211 | alpha = 0.0f; |
212 | } |
213 | } break; |
214 | case SECOND: |
215 | { |
216 | if (!smooth) |
217 | { |
218 | alpha += 0.02f; |
219 | |
220 | if (alpha >= 1.0f) smooth = true; |
221 | } |
222 | |
223 | if (smooth) alpha -= 0.02f; |
224 | |
225 | if (enemiesKill == activeEnemies) |
226 | { |
227 | enemiesKill = 0; |
228 | |
229 | for (int i = 0; i < activeEnemies; i++) |
230 | { |
231 | if (!enemy[i].active) enemy[i].active = true; |
232 | } |
233 | |
234 | activeEnemies = THIRD_WAVE; |
235 | wave = THIRD; |
236 | smooth = false; |
237 | alpha = 0.0f; |
238 | } |
239 | } break; |
240 | case THIRD: |
241 | { |
242 | if (!smooth) |
243 | { |
244 | alpha += 0.02f; |
245 | |
246 | if (alpha >= 1.0f) smooth = true; |
247 | } |
248 | |
249 | if (smooth) alpha -= 0.02f; |
250 | |
251 | if (enemiesKill == activeEnemies) victory = true; |
252 | |
253 | } break; |
254 | default: break; |
255 | } |
256 | |
257 | // Player movement |
258 | if (IsKeyDown(KEY_RIGHT)) player.rec.x += player.speed.x; |
259 | if (IsKeyDown(KEY_LEFT)) player.rec.x -= player.speed.x; |
260 | if (IsKeyDown(KEY_UP)) player.rec.y -= player.speed.y; |
261 | if (IsKeyDown(KEY_DOWN)) player.rec.y += player.speed.y; |
262 | |
263 | // Player collision with enemy |
264 | for (int i = 0; i < activeEnemies; i++) |
265 | { |
266 | if (CheckCollisionRecs(player.rec, enemy[i].rec)) gameOver = true; |
267 | } |
268 | |
269 | // Enemy behaviour |
270 | for (int i = 0; i < activeEnemies; i++) |
271 | { |
272 | if (enemy[i].active) |
273 | { |
274 | enemy[i].rec.x -= enemy[i].speed.x; |
275 | |
276 | if (enemy[i].rec.x < 0) |
277 | { |
278 | enemy[i].rec.x = GetRandomValue(screenWidth, screenWidth + 1000); |
279 | enemy[i].rec.y = GetRandomValue(0, screenHeight - enemy[i].rec.height); |
280 | } |
281 | } |
282 | } |
283 | |
284 | // Wall behaviour |
285 | if (player.rec.x <= 0) player.rec.x = 0; |
286 | if (player.rec.x + player.rec.width >= screenWidth) player.rec.x = screenWidth - player.rec.width; |
287 | if (player.rec.y <= 0) player.rec.y = 0; |
288 | if (player.rec.y + player.rec.height >= screenHeight) player.rec.y = screenHeight - player.rec.height; |
289 | |
290 | // Shoot initialization |
291 | if (IsKeyDown(KEY_SPACE)) |
292 | { |
293 | shootRate += 5; |
294 | |
295 | for (int i = 0; i < NUM_SHOOTS; i++) |
296 | { |
297 | if (!shoot[i].active && shootRate%20 == 0) |
298 | { |
299 | shoot[i].rec.x = player.rec.x; |
300 | shoot[i].rec.y = player.rec.y + player.rec.height/4; |
301 | shoot[i].active = true; |
302 | break; |
303 | } |
304 | } |
305 | } |
306 | |
307 | // Shoot logic |
308 | for (int i = 0; i < NUM_SHOOTS; i++) |
309 | { |
310 | if (shoot[i].active) |
311 | { |
312 | // Movement |
313 | shoot[i].rec.x += shoot[i].speed.x; |
314 | |
315 | // Collision with enemy |
316 | for (int j = 0; j < activeEnemies; j++) |
317 | { |
318 | if (enemy[j].active) |
319 | { |
320 | if (CheckCollisionRecs(shoot[i].rec, enemy[j].rec)) |
321 | { |
322 | shoot[i].active = false; |
323 | enemy[j].rec.x = GetRandomValue(screenWidth, screenWidth + 1000); |
324 | enemy[j].rec.y = GetRandomValue(0, screenHeight - enemy[j].rec.height); |
325 | shootRate = 0; |
326 | enemiesKill++; |
327 | score += 100; |
328 | } |
329 | |
330 | if (shoot[i].rec.x + shoot[i].rec.width >= screenWidth) |
331 | { |
332 | shoot[i].active = false; |
333 | shootRate = 0; |
334 | } |
335 | } |
336 | } |
337 | } |
338 | } |
339 | } |
340 | } |
341 | else |
342 | { |
343 | if (IsKeyPressed(KEY_ENTER)) |
344 | { |
345 | InitGame(); |
346 | gameOver = false; |
347 | } |
348 | } |
349 | } |
350 | |
351 | // Draw game (one frame) |
352 | void DrawGame(void) |
353 | { |
354 | BeginDrawing(); |
355 | |
356 | ClearBackground(RAYWHITE); |
357 | |
358 | if (!gameOver) |
359 | { |
360 | DrawRectangleRec(player.rec, player.color); |
361 | |
362 | if (wave == FIRST) DrawText("FIRST WAVE" , screenWidth/2 - MeasureText("FIRST WAVE" , 40)/2, screenHeight/2 - 40, 40, Fade(BLACK, alpha)); |
363 | else if (wave == SECOND) DrawText("SECOND WAVE" , screenWidth/2 - MeasureText("SECOND WAVE" , 40)/2, screenHeight/2 - 40, 40, Fade(BLACK, alpha)); |
364 | else if (wave == THIRD) DrawText("THIRD WAVE" , screenWidth/2 - MeasureText("THIRD WAVE" , 40)/2, screenHeight/2 - 40, 40, Fade(BLACK, alpha)); |
365 | |
366 | for (int i = 0; i < activeEnemies; i++) |
367 | { |
368 | if (enemy[i].active) DrawRectangleRec(enemy[i].rec, enemy[i].color); |
369 | } |
370 | |
371 | for (int i = 0; i < NUM_SHOOTS; i++) |
372 | { |
373 | if (shoot[i].active) DrawRectangleRec(shoot[i].rec, shoot[i].color); |
374 | } |
375 | |
376 | DrawText(TextFormat("%04i" , score), 20, 20, 40, GRAY); |
377 | |
378 | if (victory) DrawText("YOU WIN" , screenWidth/2 - MeasureText("YOU WIN" , 40)/2, screenHeight/2 - 40, 40, BLACK); |
379 | |
380 | if (pause) DrawText("GAME PAUSED" , screenWidth/2 - MeasureText("GAME PAUSED" , 40)/2, screenHeight/2 - 40, 40, GRAY); |
381 | } |
382 | else DrawText("PRESS [ENTER] TO PLAY AGAIN" , GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN" , 20)/2, GetScreenHeight()/2 - 50, 20, GRAY); |
383 | |
384 | EndDrawing(); |
385 | } |
386 | |
387 | // Unload game variables |
388 | void UnloadGame(void) |
389 | { |
390 | // TODO: Unload all dynamic loaded data (textures, sounds, models...) |
391 | } |
392 | |
393 | // Update and Draw (one frame) |
394 | void UpdateDrawFrame(void) |
395 | { |
396 | UpdateGame(); |
397 | DrawGame(); |
398 | } |
399 | |