You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

405 lines
13 KiB

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