From 1c45776bb700b55c81d5bbc5f16a4f601e602c38 Mon Sep 17 00:00:00 2001 From: themushroompirates <59015901+themushroompirates@users.noreply.github.com> Date: Wed, 15 Oct 2025 19:37:17 +0200 Subject: [PATCH] Added clock of clocks example (#5263) --- examples/shapes/shapes_clock_of_clocks.c | 227 +++++++++++++++++++++ examples/shapes/shapes_clock_of_clocks.png | Bin 0 -> 23916 bytes 2 files changed, 227 insertions(+) create mode 100644 examples/shapes/shapes_clock_of_clocks.c create mode 100644 examples/shapes/shapes_clock_of_clocks.png diff --git a/examples/shapes/shapes_clock_of_clocks.c b/examples/shapes/shapes_clock_of_clocks.c new file mode 100644 index 000000000..0418255e4 --- /dev/null +++ b/examples/shapes/shapes_clock_of_clocks.c @@ -0,0 +1,227 @@ +/******************************************************************************************* +* +* raylib [shapes] example - clock of clocks +* +* Example complexity rating: [★★☆☆] 2/4 +* +* Example originally created with raylib 5.5 +* +* Example contributed by JP Mortiboys (@themushroompirates) and reviewed by Ramon Santamaria (@raysan5) +* +* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software +* +* Copyright (c) 2025 JP Mortiboys (@themushroompirates) +* +********************************************************************************************/ + +#include "raylib.h" + +#include "raymath.h" // Required for: Lerp() +#include // Required for: time(), localtime() + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + SetConfigFlags(FLAG_MSAA_4X_HINT); + InitWindow(screenWidth, screenHeight, "raylib [shapes] example - clock of clocks"); + + const Color bgColor = ColorLerp(DARKBLUE, BLACK, 0.75f); + const Color handsColor = ColorLerp(YELLOW, RAYWHITE, .25f); + + const float clockFaceSize = 24; + const float clockFaceSpacing = 8.0f; + const float sectionSpacing = 16.0f; + + const Vector2 TL = (Vector2){ 0.0f, 90.0f }; // Top-left corner + const Vector2 TR = (Vector2){ 90.0f, 180.0f }; // Top-right corner + const Vector2 BR = (Vector2){ 180.0f, 270.0f }; // Bottom-right corner + const Vector2 BL = (Vector2){ 0.0f, 270.0f }; // Bottom-left corner + const Vector2 HH = (Vector2){ 0.0f, 180.0f }; // Horizontal line + const Vector2 VV = (Vector2){ 90.0f, 270.0f }; // Vertical line + const Vector2 ZZ = (Vector2){ 135.0f, 135.0f }; // Not relevant + + const Vector2 digitAngles[10][24] = { + /* 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 }, + /* 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 }, + /* 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 }, + /* 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 }, + /* 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 }, + /* 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 }, + /* 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 }, + /* 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 }, + /* 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 }, + /* 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 }, + }; + // Time for the hands to move to the new position (in seconds); this must be <1s + const float handsMoveDuration = .5f; + + // We store the previous seconds value so we can see if the time has changed + int prevSeconds = -1; + + // This represents the real position where the hands are right now + Vector2 currentAngles[6][24] = { 0 }; + + // This is the position where the hands were moving from + Vector2 srcAngles[6][24] = { 0 }; + // This is the position where the hands are moving to + Vector2 dstAngles[6][24] = { 0 }; + + // Current animation timer + float handsMoveTimer = 0.0f; + + // 12 or 24 hour mode + int hourMode = 24; + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + + // Get the current time + time_t rawtime; + struct tm *timeinfo; + + time(&rawtime); + timeinfo = localtime(&rawtime); + + if (timeinfo->tm_sec != prevSeconds) { + // The time has changed, so we need to move the hands to the new positions + prevSeconds = timeinfo->tm_sec; + + // Format the current time so we can access the individual digits + const char *clockDigits = TextFormat("%02d%02d%02d", timeinfo->tm_hour % hourMode, timeinfo->tm_min, timeinfo->tm_sec); + + // Fetch where we want all the hands to be + for (int digit = 0; digit < 6; digit++) { + for (int cell = 0; cell < 24; cell++) { + srcAngles[digit][cell] = currentAngles[digit][cell]; + dstAngles[digit][cell] = digitAngles[ clockDigits[digit] - '0' ][cell]; + + // Quick exception for 12h mode + if (digit == 0 && hourMode == 12 && clockDigits[0] == '0') { + dstAngles[digit][cell] = ZZ; + } + + if (srcAngles[digit][cell].x > dstAngles[digit][cell].x) { + srcAngles[digit][cell].x -= 360.0f; + } + if (srcAngles[digit][cell].y > dstAngles[digit][cell].y) { + srcAngles[digit][cell].y -= 360.0f; + } + } + } + + // Reset the timer + handsMoveTimer = -GetFrameTime(); + } + + // Now let's animate all the hands if we need to + if (handsMoveTimer < handsMoveDuration) { + // Increase the timer but don't go above the maximum + handsMoveTimer = Clamp(handsMoveTimer + GetFrameTime(), 0, handsMoveDuration); + + // Calculate the % completion of the animation + float t = handsMoveTimer / handsMoveDuration; + + // A little cheeky smoothstep + t = t * t * (3.0f - 2.0f * t); + + for (int digit = 0; digit < 6; digit++) { + for (int cell = 0; cell < 24; cell++) { + currentAngles[digit][cell].x = Lerp(srcAngles[digit][cell].x, dstAngles[digit][cell].x, t); + currentAngles[digit][cell].y = Lerp(srcAngles[digit][cell].y, dstAngles[digit][cell].y, t); + } + } + + if (handsMoveTimer == handsMoveDuration) { + // The animation has now finished + } + } + + // Handle input + + // Toggle between 12 and 24 hour mode with space + if (IsKeyPressed(KEY_SPACE)) { + hourMode = 36 - hourMode; + } + + + + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(bgColor); + + DrawText(TextFormat("%d-h mode, space to change", hourMode), 10, 30, 20, RAYWHITE); + + float xOffset = 4.0f; + + for (int digit = 0; digit < 6; digit++) { + + for (int row = 0; row < 6; row++) { + for (int col = 0; col < 4; col++) { + Vector2 centre = (Vector2){ + xOffset + col*(clockFaceSize+clockFaceSpacing) + clockFaceSize * .5f, + 100 + row*(clockFaceSize+clockFaceSpacing) + clockFaceSize * .5f + }; + DrawRing(centre, clockFaceSize * 0.5f - 2.0f, clockFaceSize * 0.5f, 0, 360, 24, DARKGRAY); + + // Big hand + DrawRectanglePro( + (Rectangle){centre.x, centre.y, clockFaceSize*.5f+4.0f, 4.0f}, + (Vector2){ 2.0f, 2.0f }, + currentAngles[digit][row*4+col].x, + handsColor + ); + + // Little hand + DrawRectanglePro( + (Rectangle){centre.x, centre.y, clockFaceSize*.5f+2.0f, 4.0f}, + (Vector2){ 2.0f, 2.0f }, + currentAngles[digit][row*4+col].y, + handsColor + ); + } + } + + xOffset += (clockFaceSize+clockFaceSpacing) * 4; + if (digit % 2 == 1) { + + DrawRing((Vector2){xOffset + 4.0f, 160.0f}, 6.0f, 8.0f, 0.0f, 360.0f, 24, handsColor); + DrawRing((Vector2){xOffset + 4.0f, 225.0f}, 6.0f, 8.0f, 0.0f, 360.0f, 24, handsColor); + + xOffset += sectionSpacing; + + } + } + + DrawFPS(10, 10); + + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/shapes/shapes_clock_of_clocks.png b/examples/shapes/shapes_clock_of_clocks.png new file mode 100644 index 0000000000000000000000000000000000000000..fb91d7263d90be64df868cbbc616fa7eb707c4ef GIT binary patch literal 23916 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ú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 literal 0 HcmV?d00001