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

333 рядки
12 KiB

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 int screenWidth = 800;
  50. static int screenHeight = 450;
  51. static int framesCounter;
  52. static bool gameOver;
  53. static bool pause;
  54. static Player player;
  55. static Ball ball;
  56. static Brick brick[LINES_OF_BRICKS][BRICKS_PER_LINE];
  57. static Vector2 brickSize;
  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: arkanoid");
  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. brickSize = (Vector2){ GetScreenWidth()/BRICKS_PER_LINE, 40 };
  107. // Initialize player
  108. player.position = (Vector2){ screenWidth/2, screenHeight*7/8 };
  109. player.size = (Vector2){ screenWidth/10, 20 };
  110. player.life = PLAYER_MAX_LIFE;
  111. // Initialize ball
  112. ball.position = (Vector2){ screenWidth/2, screenHeight*7/8 - 30 };
  113. ball.speed = (Vector2){ 0, 0 };
  114. ball.radius = 7;
  115. ball.active = false;
  116. // Initialize bricks
  117. int initialDownPosition = 50;
  118. for (int i = 0; i < LINES_OF_BRICKS; i++)
  119. {
  120. for (int j = 0; j < BRICKS_PER_LINE; j++)
  121. {
  122. brick[i][j].position = (Vector2){ j*brickSize.x + brickSize.x/2, i*brickSize.y + initialDownPosition };
  123. brick[i][j].active = true;
  124. }
  125. }
  126. }
  127. // Update game (one frame)
  128. void UpdateGame(void)
  129. {
  130. if (!gameOver)
  131. {
  132. if (IsKeyPressed('P')) pause = !pause;
  133. if (!pause)
  134. {
  135. // Player movement logic
  136. if (IsKeyDown(KEY_LEFT)) player.position.x -= 5;
  137. if ((player.position.x - player.size.x/2) <= 0) player.position.x = player.size.x/2;
  138. if (IsKeyDown(KEY_RIGHT)) player.position.x += 5;
  139. if ((player.position.x + player.size.x/2) >= screenWidth) player.position.x = screenWidth - player.size.x/2;
  140. // Ball launching logic
  141. if (!ball.active)
  142. {
  143. if (IsKeyPressed(KEY_SPACE))
  144. {
  145. ball.active = true;
  146. ball.speed = (Vector2){ 0, -5 };
  147. }
  148. }
  149. // Ball movement logic
  150. if (ball.active)
  151. {
  152. ball.position.x += ball.speed.x;
  153. ball.position.y += ball.speed.y;
  154. }
  155. else
  156. {
  157. ball.position = (Vector2){ player.position.x, screenHeight*7/8 - 30 };
  158. }
  159. // Collision logic: ball vs walls
  160. if (((ball.position.x + ball.radius) >= screenWidth) || ((ball.position.x - ball.radius) <= 0)) ball.speed.x *= -1;
  161. if ((ball.position.y - ball.radius) <= 0) ball.speed.y *= -1;
  162. if ((ball.position.y + ball.radius) >= screenHeight)
  163. {
  164. ball.speed = (Vector2){ 0, 0 };
  165. ball.active = false;
  166. player.life--;
  167. }
  168. // Collision logic: ball vs player
  169. if (CheckCollisionCircleRec(ball.position, ball.radius,
  170. (Rectangle){ player.position.x - player.size.x/2, player.position.y - player.size.y/2, player.size.x, player.size.y}))
  171. {
  172. if (ball.speed.y > 0)
  173. {
  174. ball.speed.y *= -1;
  175. ball.speed.x = (ball.position.x - player.position.x)/(player.size.x/2)*5;
  176. }
  177. }
  178. // Collision logic: ball vs bricks
  179. for (int i = 0; i < LINES_OF_BRICKS; i++)
  180. {
  181. for (int j = 0; j < BRICKS_PER_LINE; j++)
  182. {
  183. if (brick[i][j].active)
  184. {
  185. // Hit below
  186. if (((ball.position.y - ball.radius) <= (brick[i][j].position.y + brickSize.y/2)) &&
  187. ((ball.position.y - ball.radius) > (brick[i][j].position.y + brickSize.y/2 + ball.speed.y)) &&
  188. ((fabs(ball.position.x - brick[i][j].position.x)) < (brickSize.x/2 + ball.radius*2/3)) && (ball.speed.y < 0))
  189. {
  190. brick[i][j].active = false;
  191. ball.speed.y *= -1;
  192. }
  193. // Hit above
  194. else if (((ball.position.y + ball.radius) >= (brick[i][j].position.y - brickSize.y/2)) &&
  195. ((ball.position.y + ball.radius) < (brick[i][j].position.y - brickSize.y/2 + ball.speed.y)) &&
  196. ((fabs(ball.position.x - brick[i][j].position.x)) < (brickSize.x/2 + ball.radius*2/3)) && (ball.speed.y > 0))
  197. {
  198. brick[i][j].active = false;
  199. ball.speed.y *= -1;
  200. }
  201. // Hit left
  202. else if (((ball.position.x + ball.radius) >= (brick[i][j].position.x - brickSize.x/2)) &&
  203. ((ball.position.x + ball.radius) < (brick[i][j].position.x - brickSize.x/2 + ball.speed.x)) &&
  204. ((fabs(ball.position.y - brick[i][j].position.y)) < (brickSize.y/2 + ball.radius*2/3)) && (ball.speed.x > 0))
  205. {
  206. brick[i][j].active = false;
  207. ball.speed.x *= -1;
  208. }
  209. // Hit right
  210. else if (((ball.position.x - ball.radius) <= (brick[i][j].position.x + brickSize.x/2)) &&
  211. ((ball.position.x - ball.radius) > (brick[i][j].position.x + brickSize.x/2 + ball.speed.x)) &&
  212. ((fabs(ball.position.y - brick[i][j].position.y)) < (brickSize.y/2 + ball.radius*2/3)) && (ball.speed.x < 0))
  213. {
  214. brick[i][j].active = false;
  215. ball.speed.x *= -1;
  216. }
  217. }
  218. }
  219. }
  220. // Game over logic
  221. if (player.life <= 0) gameOver = true;
  222. else
  223. {
  224. gameOver = true;
  225. for (int i = 0; i < LINES_OF_BRICKS; i++)
  226. {
  227. for (int j = 0; j < BRICKS_PER_LINE; j++)
  228. {
  229. if (brick[i][j].active) gameOver = false;
  230. }
  231. }
  232. }
  233. }
  234. }
  235. else
  236. {
  237. if (IsKeyPressed(KEY_ENTER))
  238. {
  239. InitGame();
  240. gameOver = false;
  241. }
  242. }
  243. }
  244. // Draw game (one frame)
  245. void DrawGame(void)
  246. {
  247. BeginDrawing();
  248. ClearBackground(RAYWHITE);
  249. if (!gameOver)
  250. {
  251. // Draw player bar
  252. DrawRectangle(player.position.x - player.size.x/2, player.position.y - player.size.y/2, player.size.x, player.size.y, BLACK);
  253. // Draw player lives
  254. for (int i = 0; i < player.life; i++) DrawRectangle(20 + 40*i, screenHeight - 30, 35, 10, LIGHTGRAY);
  255. // Draw ball
  256. DrawCircleV(ball.position, ball.radius, MAROON);
  257. // Draw bricks
  258. for (int i = 0; i < LINES_OF_BRICKS; i++)
  259. {
  260. for (int j = 0; j < BRICKS_PER_LINE; j++)
  261. {
  262. if (brick[i][j].active)
  263. {
  264. 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);
  265. else DrawRectangle(brick[i][j].position.x - brickSize.x/2, brick[i][j].position.y - brickSize.y/2, brickSize.x, brickSize.y, DARKGRAY);
  266. }
  267. }
  268. }
  269. if (pause) DrawText("GAME PAUSED", screenWidth/2 - MeasureText("GAME PAUSED", 40)/2, screenHeight/2 - 40, 40, GRAY);
  270. }
  271. else DrawText("PRESS [ENTER] TO PLAY AGAIN", GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, GetScreenHeight()/2 - 50, 20, GRAY);
  272. EndDrawing();
  273. }
  274. // Unload game variables
  275. void UnloadGame(void)
  276. {
  277. // TODO: Unload all dynamic loaded data (textures, sounds, models...)
  278. }
  279. // Update and Draw (one frame)
  280. void UpdateDrawFrame(void)
  281. {
  282. UpdateGame();
  283. DrawGame();
  284. }