651 строка
25 KiB

6 лет назад
  1. /**********************************************************************************************
  2. *
  3. * raylib - Advance Game template
  4. *
  5. * Gameplay Screen Functions Definitions (Init, Update, Draw, Unload)
  6. *
  7. * Copyright (c) 2014-2019 Ramon Santamaria (@raysan5)
  8. *
  9. * This software is provided "as-is", without any express or implied warranty. In no event
  10. * will the authors be held liable for any damages arising from the use of this software.
  11. *
  12. * Permission is granted to anyone to use this software for any purpose, including commercial
  13. * applications, and to alter it and redistribute it freely, subject to the following restrictions:
  14. *
  15. * 1. The origin of this software must not be misrepresented; you must not claim that you
  16. * wrote the original software. If you use this software in a product, an acknowledgment
  17. * in the product documentation would be appreciated but is not required.
  18. *
  19. * 2. Altered source versions must be plainly marked as such, and must not be misrepresented
  20. * as being the original software.
  21. *
  22. * 3. This notice may not be removed or altered from any source distribution.
  23. *
  24. **********************************************************************************************/
  25. #include "raylib.h"
  26. #include "screens.h"
  27. #include "raymath.h"
  28. #include <stdio.h>
  29. #define TILE_REQUIRED_CLEAN_TIME 2 // Frames it takes to clean a dirt level
  30. #define TILE_SCORE_BY_CLEANED_LEVEL 100 // Score by cleanied dirt level
  31. #define TILE_REQUIRED_CLEAN_AREA 28*28 // Required are for actually cleaning tile
  32. #define TILE_SIZE 36 // Tile size, it should match texture
  33. #define MAX_TILES_X 32
  34. #define MAX_TILES_Y 17
  35. #define CAT_TARGET_RADIUS 3 // Target proximity radius
  36. #define CAT_DIRT_CELL_RADIUS 2 // Cells around cat for dirt spreading
  37. #define TIME_LIMIT_SECONDS 180 // Time to complete the level in seconds
  38. #define MAX_SCORE_POPUPS 60 // Maximum simultaneous score pop-ups!
  39. //----------------------------------------------------------------------------------
  40. // Module types
  41. //----------------------------------------------------------------------------------
  42. // One dirt tile type
  43. typedef struct {
  44. Vector2 position; // Relative to top-left corner
  45. int level; // Dirtiness: 0-Clean, 1-2-3-Dirt levels
  46. int state; // Current dirtiness state
  47. int counter; // Frames counter for cleaning
  48. //int time; // Time it takes to make it clean --> Depends on level
  49. //int score; // It depends on the dirt level
  50. bool cleaned; // If it was cleaned (not clean by default)
  51. } Dirtile;
  52. // Score poping-up type
  53. typedef struct {
  54. Vector2 position;
  55. int value;
  56. float alpha;
  57. bool enabled;
  58. } ScorePopup;
  59. // Furniture tile set
  60. typedef struct {
  61. int id; // Furniture tile id
  62. int posX; // Position X on tileset
  63. int posY; // Position Y on tileset
  64. int width; // Furniture piece width
  65. int height; // Furniture piece height
  66. } FurSet;
  67. // Furniture type
  68. typedef struct {
  69. int furId; // Tileset id
  70. int cellX; // Cell position X
  71. int cellY; // Cell position Y
  72. int state; // 0-Block, 1-Alpha, 2-Breakable
  73. int counter; // Counter in case of break
  74. } Furniture;
  75. //----------------------------------------------------------------------------------
  76. // Global Variables Definition (local to this module)
  77. //----------------------------------------------------------------------------------
  78. // Gameplay screen global variables
  79. static int framesCounter;
  80. static int timeLevelSeconds;
  81. static bool levelFinished;
  82. static int finishScreen;
  83. const Vector2 roomOffset = { 70, 70 };
  84. static Texture2D roomba;
  85. static Texture2D cat;
  86. static Texture2D dirtiles;
  87. static Texture2D furniture;
  88. #if defined(TILE_VIEWER_MODE)
  89. static Texture2D tracemap;
  90. static Texture2D fursetid;
  91. #endif
  92. static Music catch;
  93. static Sound fxCat[2];
  94. static Sound fxRoomba[3];
  95. static Vector2 roombaPosition = { 100, 100 };
  96. static Vector2 roombaSpeed = { 4, 4 };
  97. static int roombaTilePosX = 0, roombaTilePosY = 0;
  98. static Vector2 catPosition = { 0, 0 };
  99. static Vector2 catTargetPosition = { 0, 0 };
  100. static Vector2 catSpeed = { 3, 3 };
  101. static int catTilePosX = 0, catTilePosY = 0;
  102. static bool catShouldMove = false;
  103. static Vector2 mousePosition = { 0, 0 };
  104. static int mouseTileX = -1, mouseTileY = -1;
  105. static Dirtile tiles[MAX_TILES_X*MAX_TILES_Y] = { 0 };
  106. static ScorePopup popup[MAX_SCORE_POPUPS] = { 0 };
  107. static FurSet furset[32] = { -1 };
  108. static Furniture furmap[40] = { -1 };
  109. static int furnitureCount = 0;
  110. // Furniture collisions map
  111. // 0-block, 1-normal, 2-alpha, 3-breakable
  112. static int furcolmap[MAX_TILES_X*MAX_TILES_Y] = {
  113. 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,3,3,1,1,1,0,0,1,1,1,1,1,1,1,1,
  114. 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,3,3,1,1,1,0,0,1,1,1,1,1,1,1,1,
  115. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  116. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  117. 0,0,1,1,1,1,2,2,2,1,1,1,0,0,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,
  118. 0,0,1,1,1,1,2,2,2,1,1,1,0,0,1,1,1,2,2,2,1,1,1,1,3,3,1,1,1,1,0,0,
  119. 3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,1,1,1,3,3,1,1,1,1,0,0,
  120. 3,3,1,1,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,2,1,1,1,0,0,0,0,0,0,0,0,
  121. 1,1,1,1,2,2,2,2,2,2,2,2,1,1,1,1,1,2,2,2,1,1,1,1,0,0,0,0,0,0,0,0,
  122. 1,1,1,1,2,2,2,2,2,2,2,2,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,
  123. 1,1,1,1,0,0,0,0,0,0,0,0,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  124. 1,1,1,1,0,0,0,0,0,0,0,0,3,3,1,1,1,1,1,1,1,0,0,1,2,2,2,2,2,2,1,1,
  125. 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,2,2,2,2,2,2,1,1,
  126. 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,1,1,
  127. 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,1,1,
  128. 0,0,0,0,0,0,0,0,0,0,2,2,2,3,3,3,3,1,1,0,0,1,2,2,2,2,2,2,2,2,0,0,
  129. 0,0,0,0,0,0,0,0,0,0,2,2,2,3,3,3,3,1,1,0,0,1,2,2,2,2,2,2,2,2,0,0 };
  130. static bool showObjective = false;
  131. //----------------------------------------------------------------------------------
  132. // Module Functions Definition
  133. //----------------------------------------------------------------------------------
  134. static float GetTileCleanPercent(void);
  135. //----------------------------------------------------------------------------------
  136. // Gameplay Screen Functions Definition
  137. //----------------------------------------------------------------------------------
  138. // Gameplay Screen Initialization logic
  139. void InitGameplayScreen(void)
  140. {
  141. // Initialize GAMEPLAY screen variables here!
  142. framesCounter = 0;
  143. finishScreen = 0;
  144. timeLevelSeconds = TIME_LIMIT_SECONDS;
  145. levelFinished = false;
  146. roomba = LoadTexture("resources/roomba.png");
  147. cat = LoadTexture("resources/cat.png");
  148. dirtiles = LoadTexture("resources/dirtiles.png");
  149. furniture = LoadTexture("resources/furniture.png");
  150. #if defined(TILE_VIEWER_MODE)
  151. tracemap = LoadTexture("resources/tracemap.png");
  152. fursetid = LoadTexture("resources/fursetid.png");
  153. #endif
  154. int furCount = 0;
  155. FILE *fursetFile = fopen("resources/furset.txt", "rt");
  156. if (fursetFile != NULL)
  157. {
  158. char buffer[512] = { 0 };
  159. while (!feof(fursetFile))
  160. {
  161. fgets(buffer, 512, fursetFile);
  162. switch (buffer[0])
  163. {
  164. case 'f':
  165. {
  166. sscanf(buffer, "f %i %i %i %i %i",
  167. &furset[furCount].id,
  168. &furset[furCount].posX,
  169. &furset[furCount].posY,
  170. &furset[furCount].width,
  171. &furset[furCount].height);
  172. furCount++;
  173. } break;
  174. case '.': // This is a comment
  175. default: break;
  176. }
  177. }
  178. fclose(fursetFile);
  179. }
  180. // Position and size come in cell form, not pixels
  181. for (int i = 0; i < furCount; i++)
  182. {
  183. furset[i].posX *= TILE_SIZE;
  184. furset[i].posY *= TILE_SIZE;
  185. furset[i].width *= TILE_SIZE;
  186. furset[i].height *= TILE_SIZE;
  187. }
  188. printf("Furniture SET elements read: %i\n", furCount);
  189. // Init furniture elements
  190. FILE *furnitureFile = fopen("resources/furmap.txt", "rt");
  191. if (furnitureFile != NULL)
  192. {
  193. char buffer[512] = { 0 };
  194. while (!feof(furnitureFile))
  195. {
  196. fgets(buffer, 512, furnitureFile);
  197. switch (buffer[0])
  198. {
  199. case 'f':
  200. {
  201. sscanf(buffer, "f %i %i %i %i %i",
  202. &furmap[furnitureCount].furId,
  203. &furmap[furnitureCount].cellX,
  204. &furmap[furnitureCount].cellY,
  205. &furmap[furnitureCount].state,
  206. &furmap[furnitureCount].counter);
  207. furnitureCount++;
  208. } break;
  209. case '.': // This is a comment
  210. default: break;
  211. }
  212. }
  213. fclose(furnitureFile);
  214. }
  215. printf("Furniture MAP elements read: %i\n", furnitureCount);
  216. // Init dirt tiles
  217. for (int y = 0; y < MAX_TILES_Y; y++)
  218. {
  219. for (int x = 0; x < MAX_TILES_X; x++)
  220. {
  221. tiles[y*MAX_TILES_X + x].position = (Vector2){ roomOffset.x + TILE_SIZE*x, roomOffset.y + TILE_SIZE*y };
  222. if ((furcolmap[y*MAX_TILES_X + x] != 0) &&
  223. (furcolmap[y*MAX_TILES_X + x] != 3))
  224. {
  225. // TODO: Level of dirtiness depends on difficulty level
  226. // Adjust probability of every tile dirt level
  227. int dirt = GetRandomValue(0, 100);
  228. if (dirt < 50) tiles[y*MAX_TILES_X + x].level = 0; // 50% probability
  229. else if (dirt < 70) tiles[y*MAX_TILES_X + x].level = 1; // 20% probability
  230. else if (dirt < 90) tiles[y*MAX_TILES_X + x].level = 2; // 10% probability
  231. else if (dirt < 100) tiles[y*MAX_TILES_X + x].level = 3; // 10% probability
  232. }
  233. else tiles[y*MAX_TILES_X + x].level = 0;
  234. tiles[y*MAX_TILES_X + x].state = tiles[y*MAX_TILES_X + x].level;
  235. tiles[y*MAX_TILES_X + x].counter = (tiles[y*MAX_TILES_X + x].level == 0)? 0 : TILE_REQUIRED_CLEAN_TIME;
  236. tiles[y*MAX_TILES_X + x].cleaned = (tiles[y*MAX_TILES_X + x].level == 0)? true : false;
  237. }
  238. }
  239. // Init score popups
  240. for (int i = 0; i < MAX_SCORE_POPUPS; i++)
  241. {
  242. popup[i].position = (Vector2){ 0, 0 };
  243. popup[i].value = TILE_SCORE_BY_CLEANED_LEVEL;
  244. popup[i].enabled = false;
  245. popup[i].alpha = 1.0f;
  246. }
  247. // Init cat position
  248. catPosition = (Vector2){ 30*TILE_SIZE + roomOffset.x, TILE_SIZE + roomOffset.y };
  249. catTargetPosition = catPosition;
  250. showObjective = true;
  251. // Load music and sounds
  252. fxCat[0] = LoadSound("resources/fxcat01.wav");
  253. fxCat[1] = LoadSound("resources/fxcat02.wav");
  254. fxRoomba[0] = LoadSound("resources/fxrobot01.wav");
  255. fxRoomba[1] = LoadSound("resources/fxrobot02.wav");
  256. fxRoomba[2] = LoadSound("resources/fxrobot03.wav");
  257. catch = LoadMusicStream("resources/catch22.mod");
  258. StopMusicStream(music);
  259. SetMusicVolume(catch, 0.6f);
  260. PlayMusicStream(catch);
  261. result = 0; // Global variable: screens.h
  262. }
  263. // Gameplay Screen Update logic
  264. void UpdateGameplayScreen(void)
  265. {
  266. UpdateMusicStream(catch);
  267. if (showObjective)
  268. {
  269. if (IsKeyPressed(KEY_ENTER))
  270. {
  271. showObjective = false;
  272. PlaySound(fxCoin);
  273. }
  274. return;
  275. }
  276. framesCounter++;
  277. if (framesCounter == 60)
  278. {
  279. timeLevelSeconds--;
  280. if (timeLevelSeconds == 0)
  281. {
  282. levelFinished = true;
  283. finishScreen = 1;
  284. PlaySound(fxCoin);
  285. if (GetTileCleanPercent() >= 80) result = 1;
  286. }
  287. framesCounter = 0;
  288. }
  289. mousePosition = GetMousePosition();
  290. mouseTileX = (int)floorf((mousePosition.x - roomOffset.x)/TILE_SIZE);
  291. mouseTileY = (int)floorf((mousePosition.y - roomOffset.y)/TILE_SIZE);
  292. // Roomba movement logic
  293. Vector2 prevPosition = roombaPosition;
  294. if (IsKeyDown(KEY_D)) roombaPosition.x += roombaSpeed.x;
  295. else if (IsKeyDown(KEY_A)) roombaPosition.x -= roombaSpeed.x;
  296. if (IsKeyDown(KEY_W)) roombaPosition.y -= roombaSpeed.y;
  297. else if (IsKeyDown(KEY_S)) roombaPosition.y += roombaSpeed.y;
  298. // Verify current player position is valid or reset
  299. roombaTilePosX = (int)(floorf(roombaPosition.x - roomOffset.x)/TILE_SIZE);
  300. roombaTilePosY = (int)(floorf(roombaPosition.y - roomOffset.y)/TILE_SIZE);
  301. if ((roombaPosition.x - roomba.width/2 < roomOffset.x) ||
  302. ((roombaPosition.x + roomba.width/2) >= (roomOffset.x + MAX_TILES_X*TILE_SIZE)) ||
  303. (roombaPosition.y - roomba.height/2 < roomOffset.y) ||
  304. ((roombaPosition.y + roomba.height/2) >= (roomOffset.y + MAX_TILES_Y*TILE_SIZE)) ||
  305. (furcolmap[roombaTilePosY*MAX_TILES_X + roombaTilePosX] == 0) ||
  306. (furcolmap[roombaTilePosY*MAX_TILES_X + roombaTilePosX] == 3)) roombaPosition = prevPosition;
  307. // Dyson movement logic
  308. // if (IsKeyDown(KEY_RIGHT)) dysonPosition.x += dysonSpeed.x;
  309. // else if (IsKeyDown(KEY_LEFT)) dysonPosition.x -= dysonSpeed.x;
  310. // if (IsKeyDown(KEY_UP)) dysonPosition.y -= dysonSpeed.y;
  311. // else if (IsKeyDown(KEY_DOWN)) dysonPosition.y += dysonSpeed.y;
  312. // Check collision area between Roomba and dirt tiles to verify it's beeing cleaned
  313. // TODO: OPTIMIZATION: Check only Roomba surrounding tiles
  314. for (int y = 0; y < MAX_TILES_Y; y++)
  315. {
  316. for (int x = 0; x < MAX_TILES_X; x++)
  317. {
  318. // Check if tile requires cleaning
  319. if (tiles[y*MAX_TILES_X + x].state > 0)
  320. {
  321. // TODO: Get better collision area measure, considering round roomba
  322. Rectangle cleanRec = GetCollisionRec((Rectangle){ tiles[y*MAX_TILES_X + x].position.x, tiles[y*MAX_TILES_X + x].position.y, 36, 36 },
  323. (Rectangle){ roombaPosition.x - roomba.width/2, roombaPosition.y - roomba.height/2, roomba.width, roomba.height });
  324. // Check Roomba is covering at least half of the tile
  325. if ((cleanRec.width*cleanRec.height) > TILE_REQUIRED_CLEAN_AREA)
  326. {
  327. // Start cleaning tile
  328. tiles[y*MAX_TILES_X + x].counter--;
  329. if (tiles[y*MAX_TILES_X + x].counter < 0)
  330. {
  331. tiles[y*MAX_TILES_X + x].state--;
  332. if (tiles[y*MAX_TILES_X + x].state == 0)
  333. {
  334. tiles[y*MAX_TILES_X + x].counter = 0;
  335. score += tiles[y*MAX_TILES_X + x].level*TILE_SCORE_BY_CLEANED_LEVEL;
  336. // Show scoring popup, enable first ready!
  337. for (int i = 0; i < MAX_SCORE_POPUPS; i++)
  338. {
  339. if (!popup[i].enabled)
  340. {
  341. popup[i].position = tiles[y*MAX_TILES_X + x].position;
  342. popup[i].value = TILE_SCORE_BY_CLEANED_LEVEL*tiles[y*MAX_TILES_X + x].level;
  343. popup[i].enabled = true;
  344. popup[i].alpha = 1.0f;
  345. break;
  346. }
  347. }
  348. }
  349. else tiles[y*MAX_TILES_X + x].counter = TILE_REQUIRED_CLEAN_TIME;
  350. }
  351. }
  352. }
  353. }
  354. }
  355. // Update enabled popups!
  356. for (int i = 0; i < MAX_SCORE_POPUPS; i++)
  357. {
  358. if (popup[i].enabled)
  359. {
  360. popup[i].position.y -= 2;
  361. popup[i].alpha -= 0.015f;
  362. if (popup[i].alpha < 0.0f) popup[i].enabled = false;
  363. }
  364. }
  365. // Cat movement logic
  366. if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
  367. {
  368. // Check for a valid cell to move on
  369. if ((mousePosition.x > roomOffset.x) && (mousePosition.x < (roomOffset.x + MAX_TILES_X*TILE_SIZE)) &&
  370. (mousePosition.y > roomOffset.y) && (mousePosition.y < (roomOffset.y + MAX_TILES_Y*TILE_SIZE)) &&
  371. furcolmap[mouseTileY*MAX_TILES_X + mouseTileX] != 0)
  372. {
  373. catTargetPosition = GetMousePosition();
  374. catShouldMove = true;
  375. }
  376. }
  377. if (IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) PlaySound(fxCat[GetRandomValue(0,1)]);
  378. if (IsKeyPressed(KEY_SPACE)) PlaySound(fxRoomba[GetRandomValue(0,2)]);
  379. // Check if cat should move
  380. if (catShouldMove)
  381. {
  382. if (CheckCollisionPointCircle(catPosition, catTargetPosition, CAT_TARGET_RADIUS))
  383. {
  384. catShouldMove = false;
  385. // Spread dirt all around selected cell!
  386. // NOTE: We consider cat drawing offset
  387. catTilePosX = (int)floorf((catPosition.x - cat.width/2 - roomOffset.x)/TILE_SIZE) + 1;
  388. catTilePosY = (int)floorf((catPosition.y - cat.height/2 - 10 - roomOffset.y)/TILE_SIZE) + 1;
  389. // Check if tile includes a dirt element
  390. if (furcolmap[mouseTileY*MAX_TILES_X + mouseTileX] == 3)
  391. {
  392. for (int y = (catTilePosY - CAT_DIRT_CELL_RADIUS); y < (catTilePosY + CAT_DIRT_CELL_RADIUS + 1); y++)
  393. {
  394. for (int x = (catTilePosX - CAT_DIRT_CELL_RADIUS); x < (catTilePosX + CAT_DIRT_CELL_RADIUS + 1); x++)
  395. {
  396. if (((y >= 0) && (y < MAX_TILES_Y) && (x >= 0) && (x < MAX_TILES_X)) &&
  397. (tiles[y*MAX_TILES_X + x].state == 0) &&
  398. (furcolmap[y*MAX_TILES_X + x] != 0) &&
  399. (furcolmap[y*MAX_TILES_X + x] != 3))
  400. {
  401. int dirt = GetRandomValue(0, 100);
  402. if (dirt < 50) tiles[y*MAX_TILES_X + x].level = 0; // 50% probability
  403. else if (dirt < 70) tiles[y*MAX_TILES_X + x].level = 1; // 20% probability
  404. else if (dirt < 90) tiles[y*MAX_TILES_X + x].level = 2; // 10% probability
  405. else if (dirt < 100) tiles[y*MAX_TILES_X + x].level = 3; // 10% probability
  406. tiles[y*MAX_TILES_X + x].state = tiles[y*MAX_TILES_X + x].level;
  407. tiles[y*MAX_TILES_X + x].counter = (tiles[y*MAX_TILES_X + x].level == 0)? 0 : TILE_REQUIRED_CLEAN_TIME;
  408. tiles[y*MAX_TILES_X + x].cleaned = (tiles[y*MAX_TILES_X + x].level == 0)? true : false;
  409. }
  410. }
  411. }
  412. }
  413. }
  414. else
  415. {
  416. Vector2 dir = Vector2Subtract(catTargetPosition, catPosition);
  417. Vector2 dirnorm = Vector2Normalize(dir);
  418. catPosition.x += catSpeed.x*dirnorm.x;
  419. catPosition.y += catSpeed.y*dirnorm.y;
  420. }
  421. }
  422. if (levelFinished)
  423. {
  424. // TODO: Check level finished
  425. }
  426. }
  427. // Gameplay Screen Draw logic
  428. void DrawGameplayScreen(void)
  429. {
  430. DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), GetColor(0x57374cff));
  431. // Draw tiles
  432. for (int y = 0; y < MAX_TILES_Y; y++)
  433. {
  434. for (int x = 0; x < MAX_TILES_X; x++)
  435. {
  436. // Draw dirty tiles
  437. DrawTextureRec(dirtiles, (Rectangle){ tiles[y*MAX_TILES_X + x].state*TILE_SIZE, 0, TILE_SIZE, TILE_SIZE },
  438. (Vector2){ roomOffset.x + TILE_SIZE*x, roomOffset.y + TILE_SIZE*y }, WHITE);
  439. // TODO: Draw possible walls
  440. }
  441. }
  442. // Draw starting point for roomba and cat
  443. DrawTextureRec(furniture, (Rectangle){ furset[30].posX, furset[30].posY, furset[30].width, furset[30].height }, roomOffset, WHITE);
  444. DrawTextureRec(furniture, (Rectangle){ furset[29].posX, furset[29].posY, furset[29].width, furset[29].height }, (Vector2){ roomOffset.x + 29*36, roomOffset.y }, WHITE);
  445. DrawTexture(roomba, roombaPosition.x - roomba.width/2, roombaPosition.y - roomba.height/2, WHITE);
  446. DrawTexture(cat, catPosition.x - cat.width/2, catPosition.y - cat.height/2 - 10, WHITE);
  447. float furAlpha = 1.0f;
  448. // Draw home objects
  449. for (int i = 0; i < furnitureCount; i++)
  450. {
  451. if (CheckCollisionCircleRec((Vector2){ roombaPosition.x - roomba.width/2, roombaPosition.y - roomba.height/2 }, roomba.width,
  452. (Rectangle){ roomOffset.x + furmap[i].cellX*TILE_SIZE, roomOffset.y + furmap[i].cellY*TILE_SIZE,
  453. furset[furmap[i].furId].width, furset[furmap[i].furId].height}) && (furmap[i].state == 1))
  454. {
  455. DrawTextureRec(furniture, (Rectangle){ furset[furmap[i].furId].posX, furset[furmap[i].furId].posY, furset[furmap[i].furId].width, furset[furmap[i].furId].height },
  456. (Vector2){ roomOffset.x + furmap[i].cellX*TILE_SIZE, roomOffset.y + furmap[i].cellY*TILE_SIZE }, Fade(WHITE, 0.5f));
  457. }
  458. else
  459. {
  460. DrawTextureRec(furniture, (Rectangle){ furset[furmap[i].furId].posX, furset[furmap[i].furId].posY, furset[furmap[i].furId].width, furset[furmap[i].furId].height },
  461. (Vector2){ roomOffset.x + furmap[i].cellX*TILE_SIZE, roomOffset.y + furmap[i].cellY*TILE_SIZE }, Fade(WHITE, furAlpha));
  462. }
  463. }
  464. #if defined(TILE_VIEWER_MODE)
  465. DrawTexture(tracemap, roomOffset.x, roomOffset.y, Fade(WHITE, 0.5f));
  466. DrawTexture(fursetid, 0, 720, WHITE);
  467. #endif
  468. // TODO: If an object has been used by cat, draw it in gray
  469. // Maybe add a tempo bar for reusing?
  470. // Draw UI
  471. DrawTextEx(font2, "SCORE:", (Vector2){ 80, 10 }, font2.baseSize, 2, WHITE);
  472. DrawTextEx(font, FormatText("%i", score), (Vector2){ 260, 10 }, font.baseSize, 2, WHITE);
  473. DrawTextEx(font2, "CLEAN:", (Vector2){ 500, 10 }, font2.baseSize, 2, WHITE);
  474. DrawTextEx(font, FormatText("%.2f%%", GetTileCleanPercent()), (Vector2){ 690, 10 }, font.baseSize, 2, WHITE);
  475. DrawTextEx(font2, "TIME:", (Vector2){ 950, 10 }, font2.baseSize, 2, WHITE);
  476. DrawTextEx(font, FormatText("%i:%02is", timeLevelSeconds/60, timeLevelSeconds%60), (Vector2){ 1100, 10 }, font.baseSize, 2, WHITE);
  477. // Debug information
  478. //DrawText(FormatText("CatTilePos: [ %i, %i ]", catTilePosX, catTilePosY), roomOffset.x, 690, 20, RAYWHITE);
  479. //DrawText(FormatText("MousePos: [ %i, %i ]", mouseTileX, mouseTileY), 400, 690, 20, RED);
  480. //DrawText(FormatText("RoombaPos: [ %i, %i ]", roombaTilePosX, roombaTilePosY), 600, 690, 20, GREEN);
  481. if ((mouseTileY >= 0) && (mouseTileY < MAX_TILES_Y) && (mouseTileX >= 0) && (mouseTileX < MAX_TILES_X))
  482. {
  483. DrawRectangleLinesEx((Rectangle){ tiles[mouseTileY*MAX_TILES_X + mouseTileX].position.x,
  484. tiles[mouseTileY*MAX_TILES_X + mouseTileX].position.y, TILE_SIZE, TILE_SIZE }, 2, RED);
  485. }
  486. // Draw enabled popups!
  487. for (int i = 0; i < MAX_SCORE_POPUPS; i++)
  488. {
  489. if (popup[i].enabled) DrawText(FormatText("+%i", popup[i].value), popup[i].position.x, popup[i].position.y, 20, Fade(RED, popup[i].alpha));
  490. }
  491. // Show objective
  492. if (showObjective)
  493. {
  494. DrawRectangle(0, 150, GetScreenWidth(), GetScreenHeight() - 300, Fade(DARKGRAY, 0.7f));
  495. DrawTextEx(font2, "OBJECTIVE:", (Vector2){ 500, 240 }, font2.baseSize, 2, WHITE);
  496. DrawTextEx(font, "CLEAN 80% OF THE ROOM", (Vector2){ 300, 320 }, font.baseSize, 2, WHITE);
  497. }
  498. }
  499. // Gameplay Screen Unload logic
  500. void UnloadGameplayScreen(void)
  501. {
  502. // Unload GAMEPLAY screen variables here!
  503. UnloadTexture(roomba);
  504. UnloadTexture(cat);
  505. UnloadTexture(dirtiles);
  506. UnloadTexture(furniture);
  507. UnloadSound(fxCat[0]);
  508. UnloadSound(fxCat[1]);
  509. UnloadSound(fxRoomba[0]);
  510. UnloadSound(fxRoomba[1]);
  511. UnloadSound(fxRoomba[2]);
  512. StopMusicStream(catch);
  513. UnloadMusicStream(catch);
  514. }
  515. // Gameplay Screen should finish?
  516. int FinishGameplayScreen(void)
  517. {
  518. return finishScreen;
  519. }
  520. //----------------------------------------------------------------------------------
  521. // Module Functions Declaration
  522. //----------------------------------------------------------------------------------
  523. // Check how much cleaning we have done
  524. static float GetTileCleanPercent(void)
  525. {
  526. float value = 0;
  527. int tileLevelsToClean = 0;
  528. int tileLevelsCleaned = 0;
  529. for (int y = 0; y < MAX_TILES_Y; y++)
  530. {
  531. for (int x = 0; x < MAX_TILES_X; x++)
  532. {
  533. if (tiles[y*MAX_TILES_X + x].level > 0)
  534. {
  535. tileLevelsToClean += tiles[y*MAX_TILES_X + x].level;
  536. tileLevelsCleaned += tiles[y*MAX_TILES_X + x].state;
  537. }
  538. }
  539. }
  540. value = ((float)(tileLevelsToClean - tileLevelsCleaned)/tileLevelsToClean)*100.0f;
  541. return value;
  542. }