Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

629 linhas
24 KiB

  1. /*******************************************************************************************
  2. *
  3. * raylib - sample game: pang
  4. *
  5. * Sample game developed by Ian Eito and 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 5.0f
  23. #define PLAYER_MAX_SHOOTS 1
  24. #define MAX_BIG_BALLS 2
  25. #define BALLS_SPEED 2.0f
  26. //----------------------------------------------------------------------------------
  27. // Types and Structures Definition
  28. //----------------------------------------------------------------------------------
  29. typedef struct Player {
  30. Vector2 position;
  31. Vector2 speed;
  32. Vector3 collider;
  33. float rotation;
  34. } Player;
  35. typedef struct Shoot {
  36. Vector2 position;
  37. Vector2 speed;
  38. float radius;
  39. float rotation;
  40. int lifeSpawn;
  41. bool active;
  42. } Shoot;
  43. typedef struct Ball {
  44. Vector2 position;
  45. Vector2 speed;
  46. float radius;
  47. int points;
  48. bool active;
  49. } Ball;
  50. typedef struct Points {
  51. Vector2 position;
  52. int value;
  53. float alpha;
  54. } Points;
  55. //------------------------------------------------------------------------------------
  56. // Global Variables Declaration
  57. //------------------------------------------------------------------------------------
  58. static int screenWidth = 800;
  59. static int screenHeight = 450;
  60. static int framesCounter;
  61. static bool gameOver;
  62. static bool pause;
  63. static int score;
  64. static Player player;
  65. static Shoot shoot[PLAYER_MAX_SHOOTS];
  66. static Ball bigBalls[MAX_BIG_BALLS];
  67. static Ball mediumBalls[MAX_BIG_BALLS*2];
  68. static Ball smallBalls[MAX_BIG_BALLS*4];
  69. static Points points[5];
  70. // NOTE: Defined triangle is isosceles with common angles of 70 degrees.
  71. static float shipHeight;
  72. static float gravity;
  73. static int countmediumBallss;
  74. static int countsmallBallss;
  75. static int meteorsDestroyed;
  76. static Vector2 linePosition;
  77. static bool victory;
  78. static bool lose;
  79. static bool awake;
  80. //------------------------------------------------------------------------------------
  81. // Module Functions Declaration (local)
  82. //------------------------------------------------------------------------------------
  83. static void InitGame(void); // Initialize game
  84. static void UpdateGame(void); // Update game (one frame)
  85. static void DrawGame(void); // Draw game (one frame)
  86. static void UnloadGame(void); // Unload game
  87. static void UpdateDrawFrame(void); // Update and Draw (one frame)
  88. //------------------------------------------------------------------------------------
  89. // Program main entry point
  90. //------------------------------------------------------------------------------------
  91. int main()
  92. {
  93. InitWindow(screenWidth, screenHeight, "sample game: pang");
  94. InitGame();
  95. #if defined(PLATFORM_WEB)
  96. emscripten_set_main_loop(UpdateDrawFrame, 0, 1);
  97. #else
  98. SetTargetFPS(60);
  99. //--------------------------------------------------------------------------------------
  100. // Main game loop
  101. while (!WindowShouldClose()) // Detect window close button or ESC key
  102. {
  103. // Update
  104. //----------------------------------------------------------------------------------
  105. UpdateGame();
  106. //----------------------------------------------------------------------------------
  107. // Draw
  108. //----------------------------------------------------------------------------------
  109. DrawGame();
  110. //----------------------------------------------------------------------------------
  111. }
  112. #endif
  113. // De-Initialization
  114. //--------------------------------------------------------------------------------------
  115. UnloadGame(); // Unload loaded data (textures, sounds, models...)
  116. CloseWindow(); // Close window and OpenGL context
  117. //--------------------------------------------------------------------------------------
  118. return 0;
  119. }
  120. //------------------------------------------------------------------------------------
  121. // Module Functions Definitions (local)
  122. //------------------------------------------------------------------------------------
  123. // Initialize game variables
  124. static void InitGame(void)
  125. {
  126. int posx, posy;
  127. int velx = 0;
  128. int vely = 0;
  129. framesCounter = 0;
  130. gameOver = false;
  131. pause = false;
  132. score = 0;
  133. victory = false;
  134. lose = false;
  135. awake = true;
  136. gravity = 0.25f;
  137. linePosition = (Vector2){ 0.0f , 0.0f };
  138. shipHeight = (PLAYER_BASE_SIZE/2)/tanf(20*DEG2RAD);
  139. // Initialization player
  140. player.position = (Vector2){ screenWidth/2, screenHeight };
  141. player.speed = (Vector2){ PLAYER_SPEED, PLAYER_SPEED };
  142. player.rotation = 0;
  143. player.collider = (Vector3){ player.position.x, player.position.y - shipHeight/2.0f, 12.0f };
  144. meteorsDestroyed = 0;
  145. // Initialize shoots
  146. for (int i = 0; i < PLAYER_MAX_SHOOTS; i++)
  147. {
  148. shoot[i].position = (Vector2){ 0, 0 };
  149. shoot[i].speed = (Vector2){ 0, 0 };
  150. shoot[i].radius = 2;
  151. shoot[i].active = false;
  152. shoot[i].lifeSpawn = 0;
  153. }
  154. // Initialize big meteors
  155. for (int i = 0; i < MAX_BIG_BALLS; i++)
  156. {
  157. bigBalls[i].radius = 40.0f;
  158. posx = GetRandomValue(0 + bigBalls[i].radius, screenWidth - bigBalls[i].radius);
  159. posy = GetRandomValue(0 + bigBalls[i].radius, screenHeight/2);
  160. bigBalls[i].position = (Vector2){ posx, posy };
  161. while ((velx == 0) || (vely == 0))
  162. {
  163. velx = GetRandomValue(-BALLS_SPEED, BALLS_SPEED);
  164. vely = GetRandomValue(-BALLS_SPEED, BALLS_SPEED);
  165. }
  166. bigBalls[i].speed = (Vector2){ velx, vely };
  167. bigBalls[i].points = 200;
  168. bigBalls[i].active = true;
  169. }
  170. // Initialize medium meteors
  171. for (int i = 0; i < MAX_BIG_BALLS*2; i++)
  172. {
  173. mediumBalls[i].position = (Vector2){-100, -100};
  174. mediumBalls[i].speed = (Vector2){0,0};
  175. mediumBalls[i].radius = 20.0f;
  176. mediumBalls[i].points = 100;
  177. mediumBalls[i].active = false;
  178. }
  179. // Initialize small meteors
  180. for (int i = 0; i < MAX_BIG_BALLS*4; i++)
  181. {
  182. smallBalls[i].position = (Vector2){ -100, -100 };
  183. smallBalls[i].speed = (Vector2){ 0, 0 };
  184. smallBalls[i].radius = 10.0f;
  185. smallBalls[i].points = 50;
  186. smallBalls[i].active = false;
  187. }
  188. // Initialize animated points
  189. for (int i = 0; i < 5; i++)
  190. {
  191. points[i].position = (Vector2){ 0, 0 };
  192. points[i].value = 0;
  193. points[i].alpha = 0.0f;
  194. }
  195. countmediumBallss = 0;
  196. countsmallBallss = 0;
  197. }
  198. // Update game (one frame)
  199. void UpdateGame(void)
  200. {
  201. if (!gameOver && !victory)
  202. {
  203. if (IsKeyPressed('P')) pause = !pause;
  204. if (!pause)
  205. {
  206. // Player logic
  207. if (IsKeyDown(KEY_LEFT)) player.position.x -= player.speed.x;
  208. if (IsKeyDown(KEY_RIGHT)) player.position.x += player.speed.x;
  209. // Player vs wall collision logic
  210. if (player.position.x + PLAYER_BASE_SIZE/2 > screenWidth) player.position.x = screenWidth - PLAYER_BASE_SIZE/2;
  211. else if (player.position.x - PLAYER_BASE_SIZE/2 < 0) player.position.x = 0 + PLAYER_BASE_SIZE/2;
  212. // Player shot logic
  213. if (IsKeyPressed(KEY_SPACE))
  214. {
  215. for (int i = 0; i < PLAYER_MAX_SHOOTS; i++)
  216. {
  217. if (!shoot[i].active)
  218. {
  219. shoot[i].position = (Vector2){ player.position.x, player.position.y - shipHeight };
  220. shoot[i].speed.y = PLAYER_SPEED;
  221. shoot[i].active = true;
  222. linePosition = (Vector2){ player.position.x, player.position.y};
  223. break;
  224. }
  225. }
  226. }
  227. // Shoot life timer
  228. for (int i = 0; i < PLAYER_MAX_SHOOTS; i++)
  229. {
  230. if (shoot[i].active) shoot[i].lifeSpawn++;
  231. }
  232. // Shot logic
  233. for (int i = 0; i < PLAYER_MAX_SHOOTS; i++)
  234. {
  235. if (shoot[i].active)
  236. {
  237. shoot[i].position.y -= shoot[i].speed.y;
  238. // Shot vs walls collision logic
  239. if ((shoot[i].position.x > screenWidth + shoot[i].radius) || (shoot[i].position.x < 0 - shoot[i].radius) ||
  240. (shoot[i].position.y > screenHeight + shoot[i].radius) || (shoot[i].position.y < 0 - shoot[i].radius))
  241. {
  242. shoot[i].active = false;
  243. shoot[i].lifeSpawn = 0;
  244. }
  245. // Player shot life spawn
  246. if (shoot[i].lifeSpawn >= 120)
  247. {
  248. shoot[i].position = (Vector2){ 0.0f, 0.0f };
  249. shoot[i].speed = (Vector2){ 0.0f, 0.0f };
  250. shoot[i].lifeSpawn = 0;
  251. shoot[i].active = false;
  252. }
  253. }
  254. }
  255. // Player vs meteors collision logic
  256. player.collider = (Vector3){player.position.x, player.position.y - shipHeight/2, 12};
  257. for (int i = 0; i < MAX_BIG_BALLS; i++)
  258. {
  259. if (CheckCollisionCircles((Vector2){ player.collider.x, player.collider.y }, player.collider.z, bigBalls[i].position, bigBalls[i].radius) && bigBalls[i].active)
  260. {
  261. gameOver = true;
  262. }
  263. }
  264. for (int i = 0; i < MAX_BIG_BALLS*2; i++)
  265. {
  266. if (CheckCollisionCircles((Vector2){ player.collider.x, player.collider.y }, player.collider.z, mediumBalls[i].position, mediumBalls[i].radius) && mediumBalls[i].active)
  267. {
  268. gameOver = true;
  269. }
  270. }
  271. for (int i = 0; i < MAX_BIG_BALLS*4; i++)
  272. {
  273. if (CheckCollisionCircles((Vector2){ player.collider.x, player.collider.y }, player.collider.z, smallBalls[i].position, smallBalls[i].radius) && smallBalls[i].active)
  274. {
  275. gameOver = true;
  276. }
  277. }
  278. // Meteors logic (big)
  279. for (int i = 0; i < MAX_BIG_BALLS; i++)
  280. {
  281. if (bigBalls[i].active)
  282. {
  283. // Meteor movement logic
  284. bigBalls[i].position.x += bigBalls[i].speed.x;
  285. bigBalls[i].position.y += bigBalls[i].speed.y;
  286. // Meteor vs wall collision logic
  287. if (((bigBalls[i].position.x + bigBalls[i].radius) >= screenWidth) || ((bigBalls[i].position.x - bigBalls[i].radius) <= 0)) bigBalls[i].speed.x *= -1;
  288. if ((bigBalls[i].position.y - bigBalls[i].radius) <= 0) bigBalls[i].speed.y *= -1.5;
  289. if ((bigBalls[i].position.y + bigBalls[i].radius) >= screenHeight)
  290. {
  291. bigBalls[i].speed.y *= -1;
  292. bigBalls[i].position.y = screenHeight - bigBalls[i].radius;
  293. }
  294. bigBalls[i].speed.y += gravity;
  295. }
  296. }
  297. // Meteors logic (medium)
  298. for (int i = 0; i < MAX_BIG_BALLS*2; i++)
  299. {
  300. if (mediumBalls[i].active)
  301. {
  302. // Meteor movement logic
  303. mediumBalls[i].position.x += mediumBalls[i].speed.x;
  304. mediumBalls[i].position.y += mediumBalls[i].speed.y;
  305. // Meteor vs wall collision logic
  306. if (mediumBalls[i].position.x + mediumBalls[i].radius >= screenWidth || mediumBalls[i].position.x - mediumBalls[i].radius <= 0) mediumBalls[i].speed.x *= -1;
  307. if (mediumBalls[i].position.y - mediumBalls[i].radius <= 0) mediumBalls[i].speed.y *= -1;
  308. if (mediumBalls[i].position.y + mediumBalls[i].radius >= screenHeight)
  309. {
  310. mediumBalls[i].speed.y *= -1;
  311. mediumBalls[i].position.y = screenHeight - mediumBalls[i].radius;
  312. }
  313. mediumBalls[i].speed.y += gravity + 0.12f;
  314. }
  315. }
  316. // Meteors logic (small)
  317. for (int i = 0; i < MAX_BIG_BALLS*4; i++)
  318. {
  319. if (smallBalls[i].active)
  320. {
  321. // Meteor movement logic
  322. smallBalls[i].position.x += smallBalls[i].speed.x;
  323. smallBalls[i].position.y += smallBalls[i].speed.y;
  324. // Meteor vs wall collision logic
  325. if (smallBalls[i].position.x + smallBalls[i].radius >= screenWidth || smallBalls[i].position.x - smallBalls[i].radius <= 0) smallBalls[i].speed.x *= -1;
  326. if (smallBalls[i].position.y - smallBalls[i].radius <= 0) smallBalls[i].speed.y *= -1;
  327. if (smallBalls[i].position.y + smallBalls[i].radius >= screenHeight)
  328. {
  329. smallBalls[i].speed.y *= -1;
  330. smallBalls[i].position.y = screenHeight - smallBalls[i].radius;
  331. }
  332. smallBalls[i].speed.y += gravity + 0.25f;
  333. }
  334. }
  335. // Player-shot vs meteors logic
  336. for (int i = 0; i < PLAYER_MAX_SHOOTS; i++)
  337. {
  338. if ((shoot[i].active))
  339. {
  340. for (int a = 0; a < MAX_BIG_BALLS; a++)
  341. {
  342. if (bigBalls[a].active && (bigBalls[a].position.x - bigBalls[a].radius <= linePosition.x && bigBalls[a].position.x + bigBalls[a].radius >= linePosition.x)
  343. && (bigBalls[a].position.y + bigBalls[a].radius >= shoot[i].position.y))
  344. {
  345. shoot[i].active = false;
  346. shoot[i].lifeSpawn = 0;
  347. bigBalls[a].active = false;
  348. meteorsDestroyed++;
  349. score += bigBalls[a].points;
  350. for (int z = 0; z < 5; z++)
  351. {
  352. if (points[z].alpha == 0.0f)
  353. {
  354. points[z].position = bigBalls[a].position;
  355. points[z].value = bigBalls[a].points;
  356. points[z].alpha = 1.0f;
  357. z = 5;
  358. }
  359. }
  360. for (int j = 0; j < 2; j ++)
  361. {
  362. if ((countmediumBallss%2) == 0)
  363. {
  364. mediumBalls[countmediumBallss].position = (Vector2){bigBalls[a].position.x, bigBalls[a].position.y};
  365. mediumBalls[countmediumBallss].speed = (Vector2){ -1*BALLS_SPEED, BALLS_SPEED };
  366. }
  367. else
  368. {
  369. mediumBalls[countmediumBallss].position = (Vector2){bigBalls[a].position.x, bigBalls[a].position.y};
  370. mediumBalls[countmediumBallss].speed = (Vector2){ BALLS_SPEED, BALLS_SPEED };
  371. }
  372. mediumBalls[countmediumBallss].active = true;
  373. countmediumBallss ++;
  374. }
  375. a = MAX_BIG_BALLS;
  376. }
  377. }
  378. }
  379. if ((shoot[i].active))
  380. {
  381. for (int b = 0; b < MAX_BIG_BALLS*2; b++)
  382. {
  383. if (mediumBalls[b].active && (mediumBalls[b].position.x - mediumBalls[b].radius <= linePosition.x && mediumBalls[b].position.x + mediumBalls[b].radius >= linePosition.x)
  384. && (mediumBalls[b].position.y + mediumBalls[b].radius >= shoot[i].position.y))
  385. {
  386. shoot[i].active = false;
  387. shoot[i].lifeSpawn = 0;
  388. mediumBalls[b].active = false;
  389. meteorsDestroyed++;
  390. score += mediumBalls[b].points;
  391. for (int z = 0; z < 5; z++)
  392. {
  393. if (points[z].alpha == 0.0f)
  394. {
  395. points[z].position = mediumBalls[b].position;
  396. points[z].value = mediumBalls[b].points;
  397. points[z].alpha = 1.0f;
  398. z = 5;
  399. }
  400. }
  401. for (int j = 0; j < 2; j ++)
  402. {
  403. if (countsmallBallss%2 == 0)
  404. {
  405. smallBalls[countsmallBallss].position = (Vector2){mediumBalls[b].position.x, mediumBalls[b].position.y};
  406. smallBalls[countsmallBallss].speed = (Vector2){ BALLS_SPEED*-1, BALLS_SPEED*-1};
  407. }
  408. else
  409. {
  410. smallBalls[countsmallBallss].position = (Vector2){mediumBalls[b].position.x, mediumBalls[b].position.y};
  411. smallBalls[countsmallBallss].speed = (Vector2){ BALLS_SPEED, BALLS_SPEED*-1};
  412. }
  413. smallBalls[countsmallBallss].active = true;
  414. countsmallBallss ++;
  415. }
  416. b = MAX_BIG_BALLS*2;
  417. }
  418. }
  419. }
  420. if ((shoot[i].active))
  421. {
  422. for (int c = 0; c < MAX_BIG_BALLS*4; c++)
  423. {
  424. if (smallBalls[c].active && (smallBalls[c].position.x - smallBalls[c].radius <= linePosition.x && smallBalls[c].position.x + smallBalls[c].radius >= linePosition.x)
  425. && (smallBalls[c].position.y + smallBalls[c].radius >= shoot[i].position.y))
  426. {
  427. shoot[i].active = false;
  428. shoot[i].lifeSpawn = 0;
  429. smallBalls[c].active = false;
  430. meteorsDestroyed++;
  431. score += smallBalls[c].points;
  432. for (int z = 0; z < 5; z++)
  433. {
  434. if (points[z].alpha == 0.0f)
  435. {
  436. points[z].position = smallBalls[c].position;
  437. points[z].value = smallBalls[c].points;
  438. points[z].alpha = 1.0f;
  439. z = 5;
  440. }
  441. }
  442. c = MAX_BIG_BALLS*4;
  443. }
  444. }
  445. }
  446. }
  447. if (meteorsDestroyed == (MAX_BIG_BALLS + MAX_BIG_BALLS*2 + MAX_BIG_BALLS*4)) victory = true;
  448. }
  449. }
  450. else
  451. {
  452. if (IsKeyPressed(KEY_ENTER))
  453. {
  454. InitGame();
  455. gameOver = false;
  456. }
  457. }
  458. // Points move-up and fade logic
  459. for (int z = 0; z < 5; z++)
  460. {
  461. if (points[z].alpha > 0.0f)
  462. {
  463. points[z].position.y -= 2;
  464. points[z].alpha -= 0.02f;
  465. }
  466. if (points[z].alpha < 0.0f) points[z].alpha = 0.0f;
  467. }
  468. }
  469. // Draw game (one frame)
  470. void DrawGame(void)
  471. {
  472. BeginDrawing();
  473. ClearBackground(RAYWHITE);
  474. if (!gameOver)
  475. {
  476. // Draw player
  477. Vector2 v1 = { player.position.x + sinf(player.rotation*DEG2RAD)*(shipHeight), player.position.y - cosf(player.rotation*DEG2RAD)*(shipHeight) };
  478. Vector2 v2 = { player.position.x - cosf(player.rotation*DEG2RAD)*(PLAYER_BASE_SIZE/2), player.position.y - sinf(player.rotation*DEG2RAD)*(PLAYER_BASE_SIZE/2) };
  479. Vector2 v3 = { player.position.x + cosf(player.rotation*DEG2RAD)*(PLAYER_BASE_SIZE/2), player.position.y + sinf(player.rotation*DEG2RAD)*(PLAYER_BASE_SIZE/2) };
  480. DrawTriangle(v1, v2, v3, MAROON);
  481. // Draw meteors (big)
  482. for (int i = 0;i < MAX_BIG_BALLS; i++)
  483. {
  484. if (bigBalls[i].active) DrawCircleV(bigBalls[i].position, bigBalls[i].radius, DARKGRAY);
  485. else DrawCircleV(bigBalls[i].position, bigBalls[i].radius, Fade(LIGHTGRAY, 0.3f));
  486. }
  487. // Draw meteors (medium)
  488. for (int i = 0;i < MAX_BIG_BALLS*2; i++)
  489. {
  490. if (mediumBalls[i].active) DrawCircleV(mediumBalls[i].position, mediumBalls[i].radius, GRAY);
  491. else DrawCircleV(mediumBalls[i].position, mediumBalls[i].radius, Fade(LIGHTGRAY, 0.3f));
  492. }
  493. // Draw meteors (small)
  494. for (int i = 0;i < MAX_BIG_BALLS*4; i++)
  495. {
  496. if (smallBalls[i].active) DrawCircleV(smallBalls[i].position, smallBalls[i].radius, GRAY);
  497. else DrawCircleV(smallBalls[i].position, smallBalls[i].radius, Fade(LIGHTGRAY, 0.3f));
  498. }
  499. // Draw shoot
  500. for (int i = 0; i < PLAYER_MAX_SHOOTS; i++)
  501. {
  502. if (shoot[i].active) DrawLine(linePosition.x, linePosition.y, shoot[i].position.x, shoot[i].position.y, RED);
  503. }
  504. // Draw score points
  505. for (int z = 0; z < 5; z++)
  506. {
  507. if (points[z].alpha > 0.0f)
  508. {
  509. DrawText(FormatText("+%02i", points[z].value), points[z].position.x, points[z].position.y, 20, Fade(BLUE, points[z].alpha));
  510. }
  511. }
  512. // Draw score (UI)
  513. DrawText(FormatText("SCORE: %i", score), 10, 10, 20, LIGHTGRAY);
  514. if (victory)
  515. {
  516. DrawText("YOU WIN!", screenWidth/2 - MeasureText("YOU WIN!", 60)/2, 100, 60, LIGHTGRAY);
  517. DrawText("PRESS [ENTER] TO PLAY AGAIN", GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, GetScreenHeight()/2 - 50, 20, LIGHTGRAY);
  518. }
  519. if (pause) DrawText("GAME PAUSED", screenWidth/2 - MeasureText("GAME PAUSED", 40)/2, screenHeight/2 - 40, 40, LIGHTGRAY);
  520. }
  521. else DrawText("PRESS [ENTER] TO PLAY AGAIN", GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, GetScreenHeight()/2 - 50, 20, LIGHTGRAY);
  522. EndDrawing();
  523. }
  524. // Unload game variables
  525. void UnloadGame(void)
  526. {
  527. // TODO: Unload all dynamic loaded data (textures, sounds, models...)
  528. }
  529. // Update and Draw (one frame)
  530. void UpdateDrawFrame(void)
  531. {
  532. UpdateGame();
  533. DrawGame();
  534. }