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.

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