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

323 рядки
12 KiB

5 роки тому
5 роки тому
5 роки тому
7 роки тому
7 роки тому
7 роки тому
  1. /*******************************************************************************************
  2. *
  3. * raylib - sample game: arkanoid
  4. *
  5. * Sample game Marc Palau 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 <stdio.h>
  15. #include <stdlib.h>
  16. #include <time.h>
  17. #include <math.h>
  18. #if defined(PLATFORM_WEB)
  19. #include <emscripten/emscripten.h>
  20. #endif
  21. //----------------------------------------------------------------------------------
  22. // Some Defines
  23. //----------------------------------------------------------------------------------
  24. #define PLAYER_MAX_LIFE 5
  25. #define LINES_OF_BRICKS 5
  26. #define BRICKS_PER_LINE 20
  27. //----------------------------------------------------------------------------------
  28. // Types and Structures Definition
  29. //----------------------------------------------------------------------------------
  30. typedef enum GameScreen { LOGO, TITLE, GAMEPLAY, ENDING } GameScreen;
  31. typedef struct Player {
  32. Vector2 position;
  33. Vector2 size;
  34. int life;
  35. } Player;
  36. typedef struct Ball {
  37. Vector2 position;
  38. Vector2 speed;
  39. int radius;
  40. bool active;
  41. } Ball;
  42. typedef struct Brick {
  43. Vector2 position;
  44. bool active;
  45. } Brick;
  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 Player player = { 0 };
  54. static Ball ball = { 0 };
  55. static Brick brick[LINES_OF_BRICKS][BRICKS_PER_LINE] = { 0 };
  56. static Vector2 brickSize = { 0 };
  57. //------------------------------------------------------------------------------------
  58. // Module Functions Declaration (local)
  59. //------------------------------------------------------------------------------------
  60. static void InitGame(void); // Initialize game
  61. static void UpdateGame(void); // Update game (one frame)
  62. static void DrawGame(void); // Draw game (one frame)
  63. static void UnloadGame(void); // Unload game
  64. static void UpdateDrawFrame(void); // Update and Draw (one frame)
  65. //------------------------------------------------------------------------------------
  66. // Program main entry point
  67. //------------------------------------------------------------------------------------
  68. int main(void)
  69. {
  70. // Initialization (Note windowTitle is unused on Android)
  71. //---------------------------------------------------------
  72. InitWindow(screenWidth, screenHeight, "sample game: arkanoid");
  73. InitGame();
  74. #if defined(PLATFORM_WEB)
  75. emscripten_set_main_loop(UpdateDrawFrame, 0, 1);
  76. #else
  77. SetTargetFPS(60);
  78. //--------------------------------------------------------------------------------------
  79. // Main game loop
  80. while (!WindowShouldClose()) // Detect window close button or ESC key
  81. {
  82. // Update and Draw
  83. //----------------------------------------------------------------------------------
  84. UpdateDrawFrame();
  85. //----------------------------------------------------------------------------------
  86. }
  87. #endif
  88. // De-Initialization
  89. //--------------------------------------------------------------------------------------
  90. UnloadGame(); // Unload loaded data (textures, sounds, models...)
  91. CloseWindow(); // Close window and OpenGL context
  92. //--------------------------------------------------------------------------------------
  93. return 0;
  94. }
  95. //------------------------------------------------------------------------------------
  96. // Module Functions Definitions (local)
  97. //------------------------------------------------------------------------------------
  98. // Initialize game variables
  99. void InitGame(void)
  100. {
  101. brickSize = (Vector2){ GetScreenWidth()/BRICKS_PER_LINE, 40 };
  102. // Initialize player
  103. player.position = (Vector2){ screenWidth/2, screenHeight*7/8 };
  104. player.size = (Vector2){ screenWidth/10, 20 };
  105. player.life = PLAYER_MAX_LIFE;
  106. // Initialize ball
  107. ball.position = (Vector2){ screenWidth/2, screenHeight*7/8 - 30 };
  108. ball.speed = (Vector2){ 0, 0 };
  109. ball.radius = 7;
  110. ball.active = false;
  111. // Initialize bricks
  112. int initialDownPosition = 50;
  113. for (int i = 0; i < LINES_OF_BRICKS; i++)
  114. {
  115. for (int j = 0; j < BRICKS_PER_LINE; j++)
  116. {
  117. brick[i][j].position = (Vector2){ j*brickSize.x + brickSize.x/2, i*brickSize.y + initialDownPosition };
  118. brick[i][j].active = true;
  119. }
  120. }
  121. }
  122. // Update game (one frame)
  123. void UpdateGame(void)
  124. {
  125. if (!gameOver)
  126. {
  127. if (IsKeyPressed('P')) pause = !pause;
  128. if (!pause)
  129. {
  130. // Player movement logic
  131. if (IsKeyDown(KEY_LEFT)) player.position.x -= 5;
  132. if ((player.position.x - player.size.x/2) <= 0) player.position.x = player.size.x/2;
  133. if (IsKeyDown(KEY_RIGHT)) player.position.x += 5;
  134. if ((player.position.x + player.size.x/2) >= screenWidth) player.position.x = screenWidth - player.size.x/2;
  135. // Ball launching logic
  136. if (!ball.active)
  137. {
  138. if (IsKeyPressed(KEY_SPACE))
  139. {
  140. ball.active = true;
  141. ball.speed = (Vector2){ 0, -5 };
  142. }
  143. }
  144. // Ball movement logic
  145. if (ball.active)
  146. {
  147. ball.position.x += ball.speed.x;
  148. ball.position.y += ball.speed.y;
  149. }
  150. else
  151. {
  152. ball.position = (Vector2){ player.position.x, screenHeight*7/8 - 30 };
  153. }
  154. // Collision logic: ball vs walls
  155. if (((ball.position.x + ball.radius) >= screenWidth) || ((ball.position.x - ball.radius) <= 0)) ball.speed.x *= -1;
  156. if ((ball.position.y - ball.radius) <= 0) ball.speed.y *= -1;
  157. if ((ball.position.y + ball.radius) >= screenHeight)
  158. {
  159. ball.speed = (Vector2){ 0, 0 };
  160. ball.active = false;
  161. player.life--;
  162. }
  163. // Collision logic: ball vs player
  164. if (CheckCollisionCircleRec(ball.position, ball.radius,
  165. (Rectangle){ player.position.x - player.size.x/2, player.position.y - player.size.y/2, player.size.x, player.size.y}))
  166. {
  167. if (ball.speed.y > 0)
  168. {
  169. ball.speed.y *= -1;
  170. ball.speed.x = (ball.position.x - player.position.x)/(player.size.x/2)*5;
  171. }
  172. }
  173. // Collision logic: ball vs bricks
  174. for (int i = 0; i < LINES_OF_BRICKS; i++)
  175. {
  176. for (int j = 0; j < BRICKS_PER_LINE; j++)
  177. {
  178. if (brick[i][j].active)
  179. {
  180. // Hit below
  181. if (((ball.position.y - ball.radius) <= (brick[i][j].position.y + brickSize.y/2)) &&
  182. ((ball.position.y - ball.radius) > (brick[i][j].position.y + brickSize.y/2 + ball.speed.y)) &&
  183. ((fabs(ball.position.x - brick[i][j].position.x)) < (brickSize.x/2 + ball.radius*2/3)) && (ball.speed.y < 0))
  184. {
  185. brick[i][j].active = false;
  186. ball.speed.y *= -1;
  187. }
  188. // Hit above
  189. else if (((ball.position.y + ball.radius) >= (brick[i][j].position.y - brickSize.y/2)) &&
  190. ((ball.position.y + ball.radius) < (brick[i][j].position.y - brickSize.y/2 + ball.speed.y)) &&
  191. ((fabs(ball.position.x - brick[i][j].position.x)) < (brickSize.x/2 + ball.radius*2/3)) && (ball.speed.y > 0))
  192. {
  193. brick[i][j].active = false;
  194. ball.speed.y *= -1;
  195. }
  196. // Hit left
  197. else if (((ball.position.x + ball.radius) >= (brick[i][j].position.x - brickSize.x/2)) &&
  198. ((ball.position.x + ball.radius) < (brick[i][j].position.x - brickSize.x/2 + ball.speed.x)) &&
  199. ((fabs(ball.position.y - brick[i][j].position.y)) < (brickSize.y/2 + ball.radius*2/3)) && (ball.speed.x > 0))
  200. {
  201. brick[i][j].active = false;
  202. ball.speed.x *= -1;
  203. }
  204. // Hit right
  205. else if (((ball.position.x - ball.radius) <= (brick[i][j].position.x + brickSize.x/2)) &&
  206. ((ball.position.x - ball.radius) > (brick[i][j].position.x + brickSize.x/2 + ball.speed.x)) &&
  207. ((fabs(ball.position.y - brick[i][j].position.y)) < (brickSize.y/2 + ball.radius*2/3)) && (ball.speed.x < 0))
  208. {
  209. brick[i][j].active = false;
  210. ball.speed.x *= -1;
  211. }
  212. }
  213. }
  214. }
  215. // Game over logic
  216. if (player.life <= 0) gameOver = true;
  217. else
  218. {
  219. gameOver = true;
  220. for (int i = 0; i < LINES_OF_BRICKS; i++)
  221. {
  222. for (int j = 0; j < BRICKS_PER_LINE; j++)
  223. {
  224. if (brick[i][j].active) gameOver = false;
  225. }
  226. }
  227. }
  228. }
  229. }
  230. else
  231. {
  232. if (IsKeyPressed(KEY_ENTER))
  233. {
  234. InitGame();
  235. gameOver = false;
  236. }
  237. }
  238. }
  239. // Draw game (one frame)
  240. void DrawGame(void)
  241. {
  242. BeginDrawing();
  243. ClearBackground(RAYWHITE);
  244. if (!gameOver)
  245. {
  246. // Draw player bar
  247. DrawRectangle(player.position.x - player.size.x/2, player.position.y - player.size.y/2, player.size.x, player.size.y, BLACK);
  248. // Draw player lives
  249. for (int i = 0; i < player.life; i++) DrawRectangle(20 + 40*i, screenHeight - 30, 35, 10, LIGHTGRAY);
  250. // Draw ball
  251. DrawCircleV(ball.position, ball.radius, MAROON);
  252. // Draw bricks
  253. for (int i = 0; i < LINES_OF_BRICKS; i++)
  254. {
  255. for (int j = 0; j < BRICKS_PER_LINE; j++)
  256. {
  257. if (brick[i][j].active)
  258. {
  259. if ((i + j) % 2 == 0) DrawRectangle(brick[i][j].position.x - brickSize.x/2, brick[i][j].position.y - brickSize.y/2, brickSize.x, brickSize.y, GRAY);
  260. else DrawRectangle(brick[i][j].position.x - brickSize.x/2, brick[i][j].position.y - brickSize.y/2, brickSize.x, brickSize.y, DARKGRAY);
  261. }
  262. }
  263. }
  264. if (pause) DrawText("GAME PAUSED", screenWidth/2 - MeasureText("GAME PAUSED", 40)/2, screenHeight/2 - 40, 40, GRAY);
  265. }
  266. else DrawText("PRESS [ENTER] TO PLAY AGAIN", GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, GetScreenHeight()/2 - 50, 20, GRAY);
  267. EndDrawing();
  268. }
  269. // Unload game variables
  270. void UnloadGame(void)
  271. {
  272. // TODO: Unload all dynamic loaded data (textures, sounds, models...)
  273. }
  274. // Update and Draw (one frame)
  275. void UpdateDrawFrame(void)
  276. {
  277. UpdateGame();
  278. DrawGame();
  279. }