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//----------------------------------------------------------------------------------
32typedef enum { FIRST = 0, SECOND, THIRD } EnemyWave;
33
34typedef struct Player{
35 Rectangle rec;
36 Vector2 speed;
37 Color color;
38} Player;
39
40typedef struct Enemy{
41 Rectangle rec;
42 Vector2 speed;
43 bool active;
44 Color color;
45} Enemy;
46
47typedef struct Shoot{
48 Rectangle rec;
49 Vector2 speed;
50 bool active;
51 Color color;
52} Shoot;
53
54//------------------------------------------------------------------------------------
55// Global Variables Declaration
56//------------------------------------------------------------------------------------
57static const int screenWidth = 800;
58static const int screenHeight = 450;
59
60static bool gameOver = false;
61static bool pause = false;
62static int score = 0;
63static bool victory = false;
64
65static Player player = { 0 };
66static Enemy enemy[NUM_MAX_ENEMIES] = { 0 };
67static Shoot shoot[NUM_SHOOTS] = { 0 };
68static EnemyWave wave = { 0 };
69
70static int shootRate = 0;
71static float alpha = 0.0f;
72
73static int activeEnemies = 0;
74static int enemiesKill = 0;
75static bool smooth = false;
76
77//------------------------------------------------------------------------------------
78// Module Functions Declaration (local)
79//------------------------------------------------------------------------------------
80static void InitGame(void); // Initialize game
81static void UpdateGame(void); // Update game (one frame)
82static void DrawGame(void); // Draw game (one frame)
83static void UnloadGame(void); // Unload game
84static void UpdateDrawFrame(void); // Update and Draw (one frame)
85
86//------------------------------------------------------------------------------------
87// Program main entry point
88//------------------------------------------------------------------------------------
89int 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
127void 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)
178void 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)
352void 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
388void UnloadGame(void)
389{
390 // TODO: Unload all dynamic loaded data (textures, sounds, models...)
391}
392
393// Update and Draw (one frame)
394void UpdateDrawFrame(void)
395{
396 UpdateGame();
397 DrawGame();
398}
399