Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

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