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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 aY>0V$y}2MX6?}_2V)?SwORqRmWBwP&WT=t= literal 0 HcmV?d00001