SFML C++ analog clock

Previous topic

The SFML multimedia library treats headaches not only for newcomers to the gaming industry, but also for computer science teachers at school. The main task of which is not only to teach the child to program, but also to instill a love for application development. Using simple graphical objects and their methods, it is possible to create a game prototype or a simulator of physical and mathematical processes in a short time. In this article, we will look at the development of an analog clock in C++ using the SFML library.

Development tools

  1. visual studio with the “Development of desktop applications in C++” package installed.

  2. SFML multimedia library.

  3. Header include file SFMLWorldTime.

  4. Fonts and programming code for self-development or repository.

Preparatory work

We connect the SFML library to Visual Studio and copy the SFML library code template into the code editor.

#include <SFML/Graphics.hpp>
#include"SFMLWorldTime.h"

using namespace sf;

int main()
{
    // Создаём графическое окно размером 900х900 
    RenderWindow window(VideoMode(900, 900), L"Аналоговые часы", Style::Default);
    
    window.setVerticalSyncEnabled(true);  // Вертикальная синхронизация
    
    SFMLWorldTime etm(50, 50, 4, Color::Yellow); // Объект электронные часы
               
    while (window.isOpen())
    {
        Event event;
        while (window.pollEvent(event))
        {
            if (event.type == Event::Closed)
                window.close();
        }
        
        window.clear(Color::Blue); // Очищаем графическое окно и закрашиваем в синий цвет
        etm.drawTime(window);  // Рисуем электронные часы в графическом окне
        window.display();
    }
    return 0;
}

We add the files SFMLWorldTime.h and SFMLWorldTime.cpp and the folder with lib fonts to the project folder.

Add the SFMLWorldTime.h and SFMLWorldTime.cpp files to the project.

In the code of the program template, we write a call to the header file SFMLWorldTime.h.

#include"SFMLWorldTime.h"

Create an electronic clock object and draw it in the graphics window.

SFMLWorldTime etm(50, 50, 4, Color::Yellow);

etm.drawTime(window); 

watchmaker

#define _USE_MATH_DEFINES
#include <SFML/Graphics.hpp>
#include"SFMLWorldTime.h"
#include<math.h>


using namespace sf;
using namespace std;

int main()
{
    
    RenderWindow window(VideoMode(900, 900), L"Аналоговые часы", Style::Default);
    
    window.setVerticalSyncEnabled(true);

    SFMLWorldTime etm(50, 50, 4, Color::Yellow);

    // Корпус аналоговых часов
    CircleShape circleTime(300.f);
    circleTime.setOrigin(150, 150);
    circleTime.setPosition(303, 303);
    circleTime.setFillColor(Color::Blue);
    circleTime.setOutlineThickness(10);
    circleTime.setOutlineColor(Color::Yellow);

    // Риски аналоговых часов объявление переменных
    CircleShape PointMin;
    PointMin.setFillColor(Color::Yellow);
    float radiusNum = 280; // радиус расположения рисок
    float radiusPoint;
    float CenterClockX = 450;
    float CenterClockY = 450;
    float xPoint, yPoint;

    // Оцифровка циферблата аналоговых часов объявление переменных
    Font fontTime;
    if (!fontTime.loadFromFile("lib/dockerthree.ttf")) return 777;
    Text TimeText;
    TimeText.setFont(fontTime);
    TimeText.setCharacterSize(30);
    TimeText.setFillColor(Color::Yellow);
    float numx, numy;

    // Рисуем стрелки аналоговых часов
    RectangleShape secArrow(Vector2f(2, 280));                //секундная
    InitRect(secArrow, 453, 453, 1, 280, Color::Red);
    RectangleShape minArrow(Vector2f(8, 260));               //минутная
    InitRect(minArrow, 455, 455, 4, 260, Color::Yellow);
    RectangleShape hourArrow(Vector2f(12, 180));             //часовая
    InitRect(hourArrow, 455, 455, 6, 180, Color::Yellow);

               
    while (window.isOpen())
    {
        Event event;
        while (window.pollEvent(event))
        {
            if (event.type == Event::Closed)
                window.close();
        }
        
        window.clear(Color::Blue);
        etm.drawTime(window);     // электронные часы
        window.draw(circleTime);  // корпус аналоговых часов

        // Риски аналоговых часов 
        for (int a = 0; a < 60; a++) {
            if (a % 5 == 0)  radiusPoint = 8; else  radiusPoint = 4;
            xPoint = CenterClockX + radiusNum * cos(-6 * a * (M_PI / 180) + M_PI / 2);
            yPoint = CenterClockY - radiusNum * sin(-6 * a * (M_PI / 180) + M_PI / 2);
            PointMin.setRadius(radiusPoint);
            PointMin.setOrigin(radiusPoint / 2, radiusPoint / 2);
            PointMin.setPosition(xPoint, yPoint);
            window.draw(PointMin);
        }

        // Оцифровка циферблата аналоговых часов
        for (int i = 1; i <= 12; i++)
        {
            numx = CenterClockX + (radiusNum - 30) * cos(-30 * i * (M_PI / 180) + M_PI / 2);
            numy = CenterClockX - (radiusNum - 30) * sin(-30 * i * (M_PI / 180) + M_PI / 2);

            if (i <= 5) TimeText.setPosition(numx - 10, numy - 17);
            else  TimeText.setPosition(numx - 8, numy - 15);
            TimeText.setString(to_string(i));
            window.draw(TimeText);

        }
        secArrow.setRotation(6 * etm.getsec());                         // вращение секундной стрелки 
        minArrow.setRotation(6 * etm.getmin() + etm.getsec() * 0.1);    // вращение минутной стрелки 
        hourArrow.setRotation(30 * etm.gethour() + etm.getmin() * 0.5); // вращение часовой стрелки 

        window.draw(hourArrow); // часовая стрелка
        window.draw(minArrow);  // минутная стрелка
        window.draw(secArrow);  // секундная

        window.display();
    }
    return 0;
}

We draw a circle i.e. contour of the future clock

// Блок объявления и установки параметров объектов
    CircleShape circleTime(300.f);
    circleTime.setOrigin(150, 150);
    circleTime.setPosition(303, 303);
    circleTime.setFillColor(Color::Blue);
    circleTime.setOutlineThickness(10);
    circleTime.setOutlineColor(Color::Yellow);

// Блок отрисовки графических объектов
    window.draw(circleTime);

We connect a macro of mathematical constants

#define _USE_MATH_DEFINES

We connect the header file of mathematical functions

#include<math.h>

We declare objects and variables for drawing clock marks.

We create a circle object, which will display the circle in the form of scratches.

    // Блок объявления и установки параметров объектов
    CircleShape PointMin;                  // объект круга
    PointMin.setFillColor(Color::Yellow);  // цвет круга жёлтый

Let’s declare and initialize a real variable with the value of the distance from the center of the clock to the location of the marks.

float radiusNum = 280;

Let’s create a real variable for the size of the marks, i.e. circle object radius PointMin

float radiusPoint;

Denote by variables the coordinates of the center of the circle

float CenterClockX = 450;
float CenterClockY = 450;

Let’s declare the variables of the coordinates of the marks

float xPoint, yPoint;

Drawing risks in the graphics window

for (int a = 0; a < 60; a++) 
{
            // каждой пятой риски увеличиваем радиус
            if (a % 5 == 0)  radiusPoint = 8; else  radiusPoint = 4;
            // вычисляем координаты риски
            xPoint = CenterClockX + radiusNum * cos(-6 * a * (M_PI / 180) + M_PI / 2);
            yPoint = CenterClockY - radiusNum * sin(-6 * a * (M_PI / 180) + M_PI / 2);
            // задаём координаты и параметры риски т.е. объекту круга  PointMin
            PointMin.setRadius(radiusPoint);
            PointMin.setOrigin(radiusPoint / 2, radiusPoint / 2);
            PointMin.setPosition(xPoint, yPoint);
            // рисуем риску в графическом окне
            window.draw(PointMin);
}

In the formula for calculating the coordinates of the marks, we use mathematical constant Pi numbers – M_PI.

Let’s declare objects and variables to display the clock face

Load a font to display numbers, create a font object fontTime and load the font into it dockerthree.ttf

Font fontTime;
if (!fontTime.loadFromFile("lib/dockerthree.ttf")) return 777;

We create a text object and set its parameters: font, size and color.

    Text TimeText;
    TimeText.setFont(fontTime);
    TimeText.setCharacterSize(30);
    TimeText.setFillColor(Color::Yellow);

We declare variables for the coordinates of a text object to display numbers.

float numx, numy;

Draw a clock face in the graphics window

for (int i = 1; i <= 12; i++)
        {
            // вычисляем координаты для текстового объекта с цифрами
            numx = CenterClockX + (radiusNum - 30) * cos(-30 * i * (M_PI / 180) + M_PI / 2);
            numy = CenterClockX - (radiusNum - 30) * sin(-30 * i * (M_PI / 180) + M_PI / 2);
            // Корректируем координаты расположения цифр 
            if (i <= 5) TimeText.setPosition(numx - 10, numy - 17);
            else  TimeText.setPosition(numx - 8, numy - 15);
            // заносим значение цифры в текстовый объект
            TimeText.setString(to_string(i));
            // рисуем текстовый объект
            window.draw(TimeText);

        }

We declare objects for the clock hands and set them up.

    RectangleShape secArrow(Vector2f(2, 280));               // Секундная стрелка
    InitRect(secArrow, 453, 453, 1, 280, Color::Red);
    RectangleShape minArrow(Vector2f(8, 260));               // Минутная стрелка
    InitRect(minArrow, 455, 455, 4, 260, Color::Yellow);
    RectangleShape hourArrow(Vector2f(12, 180));             // Часовая стрелка
    InitRect(hourArrow, 455, 455, 6, 180, Color::Yellow);

Graphic display of arrows based on rectangle shape object Rectangle Shape. Setting up objects with a function InitRect (), which is located in the header file SFMLWorldTime.h.

Draw the hands of the clock

// Изменение угла положения прямоугольников т.е. стрелок
secArrow.setRotation(6 * etm.getsec());                         // Вращение секундной стрелки 
minArrow.setRotation(6 * etm.getmin() + etm.getsec() * 0.1);    // Вращение минутной стрелки 
hourArrow.setRotation(30 * etm.gethour() + etm.getmin() * 0.5); // Вращение часовой стрелки 

// Рисование стрелок в графическом окне
window.draw(hourArrow); // часовая стрелка
window.draw(minArrow);  // минутная стрелка
window.draw(secArrow);  // секундная

Method setRotation rotates the object around the specified axis, according to the rotation angle set in the method parameters.

Calculate the angle of rotation of the arrows.

The second hand will rotate through an angle equal to 360 ° / 60 sec = 6 ° (the whole circle of 360 ° is distributed over it by 60 seconds) and multiply by the current value of the seconds time.

The minute hand during this time will turn 360°/60 min = 6° times the current time value minutes and add 6°/60sec=0.1° times the number of seconds elapsed.

The hour hand during this time will turn 360°/12 hours = 30° times the current time of hours and add 30°/60min=0.5° times the elapsed minutes.

You can get more detailed instructions by watching the video “Analogue Clock SFML C++”.

Clone repository

Previous topic

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *