shapes_clock_of_clocks.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*******************************************************************************************
  2. *
  3. * raylib [shapes] example - clock of clocks
  4. *
  5. * Example complexity rating: [★★☆☆] 2/4
  6. *
  7. * Example originally created with raylib 5.5, last time updated with raylib 5.6-dev
  8. *
  9. * Example contributed by JP Mortiboys (@themushroompirates) and reviewed by Ramon Santamaria (@raysan5)
  10. *
  11. * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
  12. * BSD-like license that allows static linking with closed source software
  13. *
  14. * Copyright (c) 2025 JP Mortiboys (@themushroompirates)
  15. *
  16. ********************************************************************************************/
  17. #include "raylib.h"
  18. #include "raymath.h" // Required for: Lerp()
  19. #include <time.h> // Required for: time(), localtime()
  20. //------------------------------------------------------------------------------------
  21. // Program main entry point
  22. //------------------------------------------------------------------------------------
  23. int main(void)
  24. {
  25. // Initialization
  26. //--------------------------------------------------------------------------------------
  27. const int screenWidth = 800;
  28. const int screenHeight = 450;
  29. SetConfigFlags(FLAG_MSAA_4X_HINT);
  30. InitWindow(screenWidth, screenHeight, "raylib [shapes] example - clock of clocks");
  31. const Color bgColor = ColorLerp(DARKBLUE, BLACK, 0.75f);
  32. const Color handsColor = ColorLerp(YELLOW, RAYWHITE, .25f);
  33. const float clockFaceSize = 24;
  34. const float clockFaceSpacing = 8.0f;
  35. const float sectionSpacing = 16.0f;
  36. const Vector2 TL = (Vector2){ 0.0f, 90.0f }; // Top-left corner
  37. const Vector2 TR = (Vector2){ 90.0f, 180.0f }; // Top-right corner
  38. const Vector2 BR = (Vector2){ 180.0f, 270.0f }; // Bottom-right corner
  39. const Vector2 BL = (Vector2){ 0.0f, 270.0f }; // Bottom-left corner
  40. const Vector2 HH = (Vector2){ 0.0f, 180.0f }; // Horizontal line
  41. const Vector2 VV = (Vector2){ 90.0f, 270.0f }; // Vertical line
  42. const Vector2 ZZ = (Vector2){ 135.0f, 135.0f }; // Not relevant
  43. const Vector2 digitAngles[10][24] = {
  44. /* 0 */ { TL,HH,HH,TR, /* */ VV,TL,TR,VV,/* */ VV,VV,VV,VV,/* */ VV,VV,VV,VV,/* */ VV,BL,BR,VV,/* */ BL,HH,HH,BR },
  45. /* 1 */ { TL,HH,TR,ZZ, /* */ BL,TR,VV,ZZ,/* */ ZZ,VV,VV,ZZ,/* */ ZZ,VV,VV,ZZ,/* */ TL,BR,BL,TR,/* */ BL,HH,HH,BR },
  46. /* 2 */ { TL,HH,HH,TR, /* */ BL,HH,TR,VV,/* */ TL,HH,BR,VV,/* */ VV,TL,HH,BR,/* */ VV,BL,HH,TR,/* */ BL,HH,HH,BR },
  47. /* 3 */ { TL,HH,HH,TR, /* */ BL,HH,TR,VV,/* */ TL,HH,BR,VV,/* */ BL,HH,TR,VV,/* */ TL,HH,BR,VV,/* */ BL,HH,HH,BR },
  48. /* 4 */ { TL,TR,TL,TR, /* */ VV,VV,VV,VV,/* */ VV,BL,BR,VV,/* */ BL,HH,TR,VV,/* */ ZZ,ZZ,VV,VV,/* */ ZZ,ZZ,BL,BR },
  49. /* 5 */ { TL,HH,HH,TR, /* */ VV,TL,HH,BR,/* */ VV,BL,HH,TR,/* */ BL,HH,TR,VV,/* */ TL,HH,BR,VV,/* */ BL,HH,HH,BR },
  50. /* 6 */ { TL,HH,HH,TR, /* */ VV,TL,HH,BR,/* */ VV,BL,HH,TR,/* */ VV,TL,TR,VV,/* */ VV,BL,BR,VV,/* */ BL,HH,HH,BR },
  51. /* 7 */ { TL,HH,HH,TR, /* */ BL,HH,TR,VV,/* */ ZZ,ZZ,VV,VV,/* */ ZZ,ZZ,VV,VV,/* */ ZZ,ZZ,VV,VV,/* */ ZZ,ZZ,BL,BR },
  52. /* 8 */ { TL,HH,HH,TR, /* */ VV,TL,TR,VV,/* */ VV,BL,BR,VV,/* */ VV,TL,TR,VV,/* */ VV,BL,BR,VV,/* */ BL,HH,HH,BR },
  53. /* 9 */ { TL,HH,HH,TR, /* */ VV,TL,TR,VV,/* */ VV,BL,BR,VV,/* */ BL,HH,TR,VV,/* */ TL,HH,BR,VV,/* */ BL,HH,HH,BR },
  54. };
  55. // Time for the hands to move to the new position (in seconds); this must be <1s
  56. const float handsMoveDuration = 0.5f;
  57. int prevSeconds = -1;
  58. Vector2 currentAngles[6][24] = { 0 };
  59. Vector2 srcAngles[6][24] = { 0 };
  60. Vector2 dstAngles[6][24] = { 0 };
  61. float handsMoveTimer = 0.0f;
  62. int hourMode = 24;
  63. SetTargetFPS(60); // Set our game to run at 60 frames-per-second
  64. //--------------------------------------------------------------------------------------
  65. // Main game loop
  66. while (!WindowShouldClose()) // Detect window close button or ESC key
  67. {
  68. // Update
  69. //----------------------------------------------------------------------------------
  70. // Get the current time
  71. time_t rawtime;
  72. struct tm *timeinfo;
  73. time(&rawtime);
  74. timeinfo = localtime(&rawtime);
  75. if (timeinfo->tm_sec != prevSeconds)
  76. {
  77. // The time has changed, so we need to move the hands to the new positions
  78. prevSeconds = timeinfo->tm_sec;
  79. // Format the current time so we can access the individual digits
  80. const char *clockDigits = TextFormat("%02d%02d%02d", timeinfo->tm_hour%hourMode, timeinfo->tm_min, timeinfo->tm_sec);
  81. // Fetch where we want all the hands to be
  82. for (int digit = 0; digit < 6; digit++)
  83. {
  84. for (int cell = 0; cell < 24; cell++)
  85. {
  86. srcAngles[digit][cell] = currentAngles[digit][cell];
  87. dstAngles[digit][cell] = digitAngles[clockDigits[digit] - '0'][cell];
  88. // Quick exception for 12h mode
  89. if ((digit == 0) && (hourMode == 12) && (clockDigits[0] == '0')) dstAngles[digit][cell] = ZZ;
  90. if (srcAngles[digit][cell].x > dstAngles[digit][cell].x) srcAngles[digit][cell].x -= 360.0f;
  91. if (srcAngles[digit][cell].y > dstAngles[digit][cell].y) srcAngles[digit][cell].y -= 360.0f;
  92. }
  93. }
  94. // Reset the timer
  95. handsMoveTimer = -GetFrameTime();
  96. }
  97. // Now let's animate all the hands if we need to
  98. if (handsMoveTimer < handsMoveDuration)
  99. {
  100. // Increase the timer but don't go above the maximum
  101. handsMoveTimer = Clamp(handsMoveTimer + GetFrameTime(), 0, handsMoveDuration);
  102. // Calculate the%completion of the animation
  103. float t = handsMoveTimer/handsMoveDuration;
  104. // A little cheeky smoothstep
  105. t = t*t*(3.0f - 2.0f*t);
  106. for (int digit = 0; digit < 6; digit++)
  107. {
  108. for (int cell = 0; cell < 24; cell++)
  109. {
  110. currentAngles[digit][cell].x = Lerp(srcAngles[digit][cell].x, dstAngles[digit][cell].x, t);
  111. currentAngles[digit][cell].y = Lerp(srcAngles[digit][cell].y, dstAngles[digit][cell].y, t);
  112. }
  113. }
  114. }
  115. // Handle input
  116. if (IsKeyPressed(KEY_SPACE)) hourMode = 36 - hourMode; // Toggle between 12 and 24 hour mode with space
  117. //----------------------------------------------------------------------------------
  118. // Draw
  119. //----------------------------------------------------------------------------------
  120. BeginDrawing();
  121. ClearBackground(bgColor);
  122. DrawText(TextFormat("%d-h mode, space to change", hourMode), 10, 30, 20, RAYWHITE);
  123. float xOffset = 4.0f;
  124. for (int digit = 0; digit < 6; digit++)
  125. {
  126. for (int row = 0; row < 6; row++)
  127. {
  128. for (int col = 0; col < 4; col++)
  129. {
  130. Vector2 centre = (Vector2){
  131. xOffset + col*(clockFaceSize+clockFaceSpacing) + clockFaceSize*0.5f,
  132. 100 + row*(clockFaceSize+clockFaceSpacing) + clockFaceSize*0.5f
  133. };
  134. DrawRing(centre, clockFaceSize*0.5f - 2.0f, clockFaceSize*0.5f, 0, 360, 24, DARKGRAY);
  135. // Big hand
  136. DrawRectanglePro(
  137. (Rectangle){centre.x, centre.y, clockFaceSize*0.5f+4.0f, 4.0f},
  138. (Vector2){ 2.0f, 2.0f },
  139. currentAngles[digit][row*4+col].x,
  140. handsColor
  141. );
  142. // Little hand
  143. DrawRectanglePro(
  144. (Rectangle){centre.x, centre.y, clockFaceSize*0.5f+2.0f, 4.0f},
  145. (Vector2){ 2.0f, 2.0f },
  146. currentAngles[digit][row*4+col].y,
  147. handsColor
  148. );
  149. }
  150. }
  151. xOffset += (clockFaceSize+clockFaceSpacing)*4;
  152. if (digit%2 == 1)
  153. {
  154. DrawRing((Vector2){xOffset + 4.0f, 160.0f}, 6.0f, 8.0f, 0.0f, 360.0f, 24, handsColor);
  155. DrawRing((Vector2){xOffset + 4.0f, 225.0f}, 6.0f, 8.0f, 0.0f, 360.0f, 24, handsColor);
  156. xOffset += sectionSpacing;
  157. }
  158. }
  159. DrawFPS(10, 10);
  160. EndDrawing();
  161. //----------------------------------------------------------------------------------
  162. }
  163. // De-Initialization
  164. //--------------------------------------------------------------------------------------
  165. CloseWindow(); // Close window and OpenGL context
  166. //--------------------------------------------------------------------------------------
  167. return 0;
  168. }