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.

382 lines
14 KiB

  1. /*******************************************************************************************
  2. *
  3. * raylib - sample game: asteroids survival
  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. #include <math.h>
  15. #if defined(PLATFORM_WEB)
  16. #include <emscripten/emscripten.h>
  17. #endif
  18. //----------------------------------------------------------------------------------
  19. // Some Defines
  20. //----------------------------------------------------------------------------------
  21. #define PLAYER_BASE_SIZE 20.0f
  22. #define PLAYER_SPEED 6.0f
  23. #define PLAYER_MAX_SHOOTS 10
  24. #define METEORS_SPEED 2
  25. #define MAX_MEDIUM_METEORS 8
  26. #define MAX_SMALL_METEORS 16
  27. //----------------------------------------------------------------------------------
  28. // Types and Structures Definition
  29. //----------------------------------------------------------------------------------
  30. typedef struct Player {
  31. Vector2 position;
  32. Vector2 speed;
  33. float acceleration;
  34. float rotation;
  35. Vector3 collider;
  36. Color color;
  37. } Player;
  38. typedef struct Meteor {
  39. Vector2 position;
  40. Vector2 speed;
  41. float radius;
  42. bool active;
  43. Color color;
  44. } Meteor;
  45. //------------------------------------------------------------------------------------
  46. // Global Variables Declaration
  47. //------------------------------------------------------------------------------------
  48. static int screenWidth = 800;
  49. static int screenHeight = 450;
  50. static int framesCounter;
  51. static bool gameOver;
  52. static bool pause;
  53. // NOTE: Defined triangle is isosceles with common angles of 70 degrees.
  54. static float shipHeight;
  55. static Player player;
  56. static Meteor mediumMeteor[MAX_MEDIUM_METEORS];
  57. static Meteor smallMeteor[MAX_SMALL_METEORS];
  58. //------------------------------------------------------------------------------------
  59. // Module Functions Declaration (local)
  60. //------------------------------------------------------------------------------------
  61. static void InitGame(void); // Initialize game
  62. static void UpdateGame(void); // Update game (one frame)
  63. static void DrawGame(void); // Draw game (one frame)
  64. static void UnloadGame(void); // Unload game
  65. static void UpdateDrawFrame(void); // Update and Draw (one frame)
  66. //------------------------------------------------------------------------------------
  67. // Program main entry point
  68. //------------------------------------------------------------------------------------
  69. int main()
  70. {
  71. // Initialization
  72. //--------------------------------------------------------------------------------------
  73. InitWindow(screenWidth, screenHeight, "sample game: asteroids survival");
  74. InitGame();
  75. #if defined(PLATFORM_WEB)
  76. emscripten_set_main_loop(UpdateDrawFrame, 0, 1);
  77. #else
  78. SetTargetFPS(60);
  79. //--------------------------------------------------------------------------------------
  80. // Main game loop
  81. while (!WindowShouldClose()) // Detect window close button or ESC key
  82. {
  83. // Update
  84. //----------------------------------------------------------------------------------
  85. UpdateGame();
  86. //----------------------------------------------------------------------------------
  87. // Draw
  88. //----------------------------------------------------------------------------------
  89. DrawGame();
  90. //----------------------------------------------------------------------------------
  91. }
  92. #endif
  93. // De-Initialization
  94. //--------------------------------------------------------------------------------------
  95. UnloadGame(); // Unload loaded data (textures, sounds, models...)
  96. CloseWindow(); // Close window and OpenGL context
  97. //--------------------------------------------------------------------------------------
  98. return 0;
  99. }
  100. //------------------------------------------------------------------------------------
  101. // Module Functions Definitions (local)
  102. //------------------------------------------------------------------------------------
  103. // Initialize game variables
  104. void InitGame(void)
  105. {
  106. int posx, posy;
  107. int velx, vely;
  108. bool correctRange = false;
  109. pause = false;
  110. framesCounter = 0;
  111. shipHeight = (PLAYER_BASE_SIZE/2)/tanf(20*DEG2RAD);
  112. // Initialization player
  113. player.position = (Vector2){screenWidth/2, screenHeight/2 - shipHeight/2};
  114. player.speed = (Vector2){0, 0};
  115. player.acceleration = 0;
  116. player.rotation = 0;
  117. player.collider = (Vector3){player.position.x + sin(player.rotation*DEG2RAD)*(shipHeight/2.5f), player.position.y - cos(player.rotation*DEG2RAD)*(shipHeight/2.5f), 12};
  118. player.color = LIGHTGRAY;
  119. for (int i = 0; i < MAX_MEDIUM_METEORS; i++)
  120. {
  121. posx = GetRandomValue(0, screenWidth);
  122. while(!correctRange)
  123. {
  124. if (posx > screenWidth/2 - 150 && posx < screenWidth/2 + 150) posx = GetRandomValue(0, screenWidth);
  125. else correctRange = true;
  126. }
  127. correctRange = false;
  128. posy = GetRandomValue(0, screenHeight);
  129. while(!correctRange)
  130. {
  131. if (posy > screenHeight/2 - 150 && posy < screenHeight/2 + 150) posy = GetRandomValue(0, screenHeight);
  132. else correctRange = true;
  133. }
  134. correctRange = false;
  135. velx = GetRandomValue(-METEORS_SPEED, METEORS_SPEED);
  136. vely = GetRandomValue(-METEORS_SPEED, METEORS_SPEED);
  137. while(!correctRange)
  138. {
  139. if (velx == 0 && vely == 0)
  140. {
  141. velx = GetRandomValue(-METEORS_SPEED, METEORS_SPEED);
  142. vely = GetRandomValue(-METEORS_SPEED, METEORS_SPEED);
  143. }
  144. else correctRange = true;
  145. }
  146. mediumMeteor[i].position = (Vector2){posx, posy};
  147. mediumMeteor[i].speed = (Vector2){velx, vely};
  148. mediumMeteor[i].radius = 20;
  149. mediumMeteor[i].active = true;
  150. mediumMeteor[i].color = GREEN;
  151. }
  152. for (int i = 0; i < MAX_SMALL_METEORS; i++)
  153. {
  154. posx = GetRandomValue(0, screenWidth);
  155. while(!correctRange)
  156. {
  157. if (posx > screenWidth/2 - 150 && posx < screenWidth/2 + 150) posx = GetRandomValue(0, screenWidth);
  158. else correctRange = true;
  159. }
  160. correctRange = false;
  161. posy = GetRandomValue(0, screenHeight);
  162. while(!correctRange)
  163. {
  164. if (posy > screenHeight/2 - 150 && posy < screenHeight/2 + 150) posy = GetRandomValue(0, screenHeight);
  165. else correctRange = true;
  166. }
  167. correctRange = false;
  168. velx = GetRandomValue(-METEORS_SPEED, METEORS_SPEED);
  169. vely = GetRandomValue(-METEORS_SPEED, METEORS_SPEED);
  170. while(!correctRange)
  171. {
  172. if (velx == 0 && vely == 0)
  173. {
  174. velx = GetRandomValue(-METEORS_SPEED, METEORS_SPEED);
  175. vely = GetRandomValue(-METEORS_SPEED, METEORS_SPEED);
  176. }
  177. else correctRange = true;
  178. }
  179. smallMeteor[i].position = (Vector2){posx, posy};
  180. smallMeteor[i].speed = (Vector2){velx, vely};
  181. smallMeteor[i].radius = 10;
  182. smallMeteor[i].active = true;
  183. smallMeteor[i].color = YELLOW;
  184. }
  185. }
  186. // Update game (one frame)
  187. void UpdateGame(void)
  188. {
  189. if (!gameOver)
  190. {
  191. if (IsKeyPressed('P')) pause = !pause;
  192. if (!pause)
  193. {
  194. framesCounter++;
  195. // Player logic
  196. // Rotation
  197. if (IsKeyDown(KEY_LEFT)) player.rotation -= 5;
  198. if (IsKeyDown(KEY_RIGHT)) player.rotation += 5;
  199. // Speed
  200. player.speed.x = sin(player.rotation*DEG2RAD)*PLAYER_SPEED;
  201. player.speed.y = cos(player.rotation*DEG2RAD)*PLAYER_SPEED;
  202. // Controller
  203. if (IsKeyDown(KEY_UP))
  204. {
  205. if (player.acceleration < 1) player.acceleration += 0.04f;
  206. }
  207. else
  208. {
  209. if (player.acceleration > 0) player.acceleration -= 0.02f;
  210. else if (player.acceleration < 0) player.acceleration = 0;
  211. }
  212. if (IsKeyDown(KEY_DOWN))
  213. {
  214. if (player.acceleration > 0) player.acceleration -= 0.04f;
  215. else if (player.acceleration < 0) player.acceleration = 0;
  216. }
  217. // Movement
  218. player.position.x += (player.speed.x*player.acceleration);
  219. player.position.y -= (player.speed.y*player.acceleration);
  220. // Wall behaviour for player
  221. if (player.position.x > screenWidth + shipHeight) player.position.x = -(shipHeight);
  222. else if (player.position.x < -(shipHeight)) player.position.x = screenWidth + shipHeight;
  223. if (player.position.y > (screenHeight + shipHeight)) player.position.y = -(shipHeight);
  224. else if (player.position.y < -(shipHeight)) player.position.y = screenHeight + shipHeight;
  225. // Collision Player to meteors
  226. player.collider = (Vector3){player.position.x + sin(player.rotation*DEG2RAD)*(shipHeight/2.5f), player.position.y - cos(player.rotation*DEG2RAD)*(shipHeight/2.5f), 12};
  227. for (int a = 0; a < MAX_MEDIUM_METEORS; a++)
  228. {
  229. if (CheckCollisionCircles((Vector2){player.collider.x, player.collider.y}, player.collider.z, mediumMeteor[a].position, mediumMeteor[a].radius) && mediumMeteor[a].active) gameOver = true;
  230. }
  231. for (int a = 0; a < MAX_SMALL_METEORS; a++)
  232. {
  233. if (CheckCollisionCircles((Vector2){player.collider.x, player.collider.y}, player.collider.z, smallMeteor[a].position, smallMeteor[a].radius) && smallMeteor[a].active) gameOver = true;
  234. }
  235. // Meteor logic
  236. for (int i = 0; i < MAX_MEDIUM_METEORS; i++)
  237. {
  238. if (mediumMeteor[i].active)
  239. {
  240. // movement
  241. mediumMeteor[i].position.x += mediumMeteor[i].speed.x;
  242. mediumMeteor[i].position.y += mediumMeteor[i].speed.y;
  243. // wall behaviour
  244. if (mediumMeteor[i].position.x > screenWidth + mediumMeteor[i].radius) mediumMeteor[i].position.x = -(mediumMeteor[i].radius);
  245. else if (mediumMeteor[i].position.x < 0 - mediumMeteor[i].radius) mediumMeteor[i].position.x = screenWidth + mediumMeteor[i].radius;
  246. if (mediumMeteor[i].position.y > screenHeight + mediumMeteor[i].radius) mediumMeteor[i].position.y = -(mediumMeteor[i].radius);
  247. else if (mediumMeteor[i].position.y < 0 - mediumMeteor[i].radius) mediumMeteor[i].position.y = screenHeight + mediumMeteor[i].radius;
  248. }
  249. }
  250. for (int i = 0; i < MAX_SMALL_METEORS; i++)
  251. {
  252. if (smallMeteor[i].active)
  253. {
  254. // movement
  255. smallMeteor[i].position.x += smallMeteor[i].speed.x;
  256. smallMeteor[i].position.y += smallMeteor[i].speed.y;
  257. // wall behaviour
  258. if (smallMeteor[i].position.x > screenWidth + smallMeteor[i].radius) smallMeteor[i].position.x = -(smallMeteor[i].radius);
  259. else if (smallMeteor[i].position.x < 0 - smallMeteor[i].radius) smallMeteor[i].position.x = screenWidth + smallMeteor[i].radius;
  260. if (smallMeteor[i].position.y > screenHeight + smallMeteor[i].radius) smallMeteor[i].position.y = -(smallMeteor[i].radius);
  261. else if (smallMeteor[i].position.y < 0 - smallMeteor[i].radius) smallMeteor[i].position.y = screenHeight + smallMeteor[i].radius;
  262. }
  263. }
  264. }
  265. }
  266. else
  267. {
  268. if (IsKeyPressed(KEY_ENTER))
  269. {
  270. InitGame();
  271. gameOver = false;
  272. }
  273. }
  274. }
  275. // Draw game (one frame)
  276. void DrawGame(void)
  277. {
  278. BeginDrawing();
  279. ClearBackground(RAYWHITE);
  280. if (!gameOver)
  281. {
  282. // Draw spaceship
  283. Vector2 v1 = { player.position.x + sinf(player.rotation*DEG2RAD)*(shipHeight), player.position.y - cosf(player.rotation*DEG2RAD)*(shipHeight) };
  284. Vector2 v2 = { player.position.x - cosf(player.rotation*DEG2RAD)*(PLAYER_BASE_SIZE/2), player.position.y - sinf(player.rotation*DEG2RAD)*(PLAYER_BASE_SIZE/2) };
  285. Vector2 v3 = { player.position.x + cosf(player.rotation*DEG2RAD)*(PLAYER_BASE_SIZE/2), player.position.y + sinf(player.rotation*DEG2RAD)*(PLAYER_BASE_SIZE/2) };
  286. DrawTriangle(v1, v2, v3, MAROON);
  287. // Draw meteor
  288. for (int i = 0;i < MAX_MEDIUM_METEORS; i++)
  289. {
  290. if (mediumMeteor[i].active) DrawCircleV(mediumMeteor[i].position, mediumMeteor[i].radius, GRAY);
  291. else DrawCircleV(mediumMeteor[i].position, mediumMeteor[i].radius, Fade(LIGHTGRAY, 0.3f));
  292. }
  293. for (int i = 0;i < MAX_SMALL_METEORS; i++)
  294. {
  295. if (smallMeteor[i].active) DrawCircleV(smallMeteor[i].position, smallMeteor[i].radius, DARKGRAY);
  296. else DrawCircleV(smallMeteor[i].position, smallMeteor[i].radius, Fade(LIGHTGRAY, 0.3f));
  297. }
  298. DrawText(FormatText("TIME: %.02f", (float)framesCounter/60), 10, 10, 20, BLACK);
  299. if (pause) DrawText("GAME PAUSED", screenWidth/2 - MeasureText("GAME PAUSED", 40)/2, screenHeight/2 - 40, 40, GRAY);
  300. }
  301. else DrawText("PRESS [ENTER] TO PLAY AGAIN", GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, GetScreenHeight()/2 - 50, 20, GRAY);
  302. EndDrawing();
  303. //----------------------------------------------------------------------------------
  304. }
  305. // Unload game variables
  306. void UnloadGame(void)
  307. {
  308. // TODO: Unload all dynamic loaded data (textures, sounds, models...)
  309. }
  310. // Update and Draw (one frame)
  311. void UpdateDrawFrame(void)
  312. {
  313. UpdateGame();
  314. DrawGame();
  315. }