VOLVER

TUTORIAL DE SFML

 

CAPITULO 2

En este capítulo realizamos un reloj de dos tipos, digital y analógico.
Aprenderemos a manejar los textos, líneas y círculos.

Reloj digital
#include "SFML/Graphics.hpp"
#include "SFML/Window.hpp"
#include "SFML/System.hpp"

#include "math.h"

char VARI[100];
std::string CADENAStr;


int main()
{
    time_t hora;
    struct tm *phora;

    int segundos;

    sf::RenderWindow ventana(sf::VideoMode(800, 600), "MI VENTANA", sf::Style::Close);
    ventana.setFramerateLimit(4);

    sf::Font font;
    if (!font.loadFromFile("sansation.ttf")) throw("¡FUENTES NO ENCONTRADAS!");

    sf::Text miTexto;
    miTexto.setFont(font);

    sf::Event evento;
    while (ventana.isOpen()) {
   
    hora = time(NULL);
    phora = localtime(&hora);

    if (segundos != phora->tm_sec) {
        segundos = phora->tm_sec;
        // Estilo C normal
        sprintf(VARI, "TIME %02d:%02d:%02d", phora->tm_hour, phora->tm_min, phora->tm_sec);
        //printf("%s \n", VARI);

        ventana.clear(sf::Color::White);

        CADENAStr = std::string(VARI);
        miTexto.setString(CADENAStr);
        miTexto.setFillColor(sf::Color::Red);
        miTexto.setOutlineThickness(0.f);
        miTexto.setLetterSpacing(1.f);
        miTexto.setCharacterSize(40);
        miTexto.setPosition(20, 10);
        ventana.draw(miTexto);

        // Estilo C++
        CADENAStr = "TIME " + std::to_string(phora->tm_hour) + ":" + std::to_string(phora->tm_min) + ":" + std::to_string(phora->tm_sec);
        miTexto.setString(CADENAStr);
        miTexto.setFillColor(sf::Color::Blue);
        miTexto.setLetterSpacing(2.f);
        miTexto.setCharacterSize(60);
        miTexto.setPosition(20, 60);
        ventana.draw(miTexto);

        miTexto.setFillColor(sf::Color::Yellow);
        miTexto.setOutlineColor(sf::Color {  0x8ECF3CFF} );
        miTexto.setOutlineThickness(5.f);
        miTexto.setCharacterSize(60);
        miTexto.setPosition(20, 130);
        ventana.draw(miTexto);
       
        ventana.display();
    }


    while (ventana.pollEvent(evento)) {
        if (evento.type == sf::Event::Closed) {
        printf("Cerrando ventana SFML\n");
        ventana.close();
        }
     }

    }
}


En este programa obtenemos la hora local y la almacenamos en la estructura phora.
La horas están en phora->tm_hour ,  minutos en phora->tm_min , segundos en phora->tm_sec .
Como yo provengo de C , estoy mas acostumbrado a utilizar las cadena normales.
He realizado dos métodos para la impresión de la hora, que cada uno use lo que le guste mas.
En método de C es pasar todos los valores con sprinf a la cadena VARI, para luego transformarla al string CADENAStr.
En el método C++ se concatena varios string transformados con std::to_string(int numero) , y juntarlos al string CADENAStr.
Creamos una clase llamada sf::Text miTexto en la cual cambiaremos varios parámetros a nuestro gusto.
           miTexto.setString(CADENAStr);
        miTexto.setFillColor(sf::Color::Blue);
        miTexto.setLetterSpacing(2.f);
        miTexto.setCharacterSize(60);
        miTexto.setPosition(20, 60);
Solo nos queda imprimir en la ventana con la orden ventana.draw(miTexto) .
He creado 3 tipos de letras para que imaginéis la cantidad de formas que se pueden hacer.
Como el programa no necesita muchas imágenes por segundo, solo imprime la pantalla cada vez que cambian los segundos.
Además utilizando la orden ventana.setFramerateLimit(4) , hacemos que como mucho compruebe el cambio de segundos cada 4 segundos, esto se llama ahorrar carga al ordenador.



Reloj analógico
#include "SFML/Graphics.hpp"
#include "SFML/Window.hpp"
#include "SFML/System.hpp"

#include "math.h"

char VARI[100];
std::string CADENAStr;

int main()
{
    time_t hora;
    struct tm *phora;

    //Reloj Analogico______________________________________
    float sx = 0, sy = 1, mx = 1, my = 0, hx = -1, hy = 0;
    unsigned int x0 = 0, x1 = 0, y0 = 0, y1 = 0;
    float sdeg = 0, mdeg = 0, hdeg = 0;
    //_____________________________________________________

    int segundos;

    sf::Vertex lineReloj[2];

    sf::RenderWindow ventana(sf::VideoMode(800, 600), "MI VENTANA", sf::Style::Close);
    ventana.setFramerateLimit(4);

    sf::Font font;
    if (!font.loadFromFile("sansation.ttf")) throw("¡FUENTES NO ENCONTRADAS!");

    sf::Text miTexto;
    miTexto.setFont(font);

    sf::Event evento;
    while (ventana.isOpen()) {

    hora = time(NULL);
    phora = localtime(&hora);

    if (segundos != phora->tm_sec) {
        segundos = phora->tm_sec;
       
        // Estilo C normal
        sprintf(VARI, "TIME %02d:%02d:%02d", phora->tm_hour, phora->tm_min, phora->tm_sec);
        //printf("%s \n", VARI);

        ventana.clear(sf::Color::White);
        CADENAStr = std::string(VARI);
        miTexto.setString(CADENAStr);
        miTexto.setFillColor(sf::Color::Red);
        miTexto.setOutlineThickness(0.f);
        miTexto.setLetterSpacing(1.f);
        miTexto.setCharacterSize(40);
        miTexto.setPosition(20, 10);
        ventana.draw(miTexto);

// Dibujar reloj analógico_______________________________
#define LUGARX 400
#define LUGARY 340
#define CIRCULOR1 120
#define CIRCULOR2 110

        sf::CircleShape circulo1(120);
        circulo1.setPosition(LUGARX - 120, LUGARY - 120);
        circulo1.setFillColor(sf::Color::Transparent);
        circulo1.setOutlineThickness(2);
        circulo1.setOutlineColor(sf::Color::Blue);

        ventana.draw(circulo1);

        for (int i = 0; i < 360; i += 30) {
        sx = cos((i - 90) * 0.0174532925);
        sy = sin((i - 90) * 0.0174532925);
        x0 = sx * CIRCULOR1 + LUGARX;
        y0 = sy * CIRCULOR1 + LUGARY;
        x1 = sx * CIRCULOR2 + LUGARX;
        y1 = sy * CIRCULOR2 + LUGARY;

        lineReloj[0] = sf::Vertex(sf::Vector2f(x0, y0), sf::Color::Blue);
        lineReloj[1] = sf::Vertex(sf::Vector2f(x1, y1), sf::Color::Blue);
        ventana.draw(lineReloj, 2, sf::Lines);
        }

        //SEGUNDOS
        sdeg = phora->tm_sec * 6;    // 0-59 -> 0-354
        sx = cos((sdeg - 90) * 0.0174532925);
        sy = sin((sdeg - 90) * 0.0174532925);
        lineReloj[0] = sf::Vertex(sf::Vector2f(LUGARX, LUGARY), sf::Color::Red);
        lineReloj[1] = sf::Vertex(sf::Vector2f(sx * CIRCULOR2 + LUGARX, sy * CIRCULOR2 + LUGARY), sf::Color::Red);
        ventana.draw(lineReloj, 2, sf::Lines);
        //MINUTOS 
        //mdeg = phora->tm_min * 6 + sdeg * 0.01666667;
        mdeg = phora->tm_min * 6;
        mx = cos((mdeg - 90) * 0.0174532925);
        my = sin((mdeg - 90) * 0.0174532925);
        lineReloj[0] = sf::Vertex(sf::Vector2f(LUGARX, LUGARY), sf::Color::Black);
        lineReloj[1] = sf::Vertex(sf::Vector2f(mx * 100 + LUGARX, my * 100 + LUGARY), sf::Color::Black);
        ventana.draw(lineReloj, 2, sf::Lines);
        //HORA
        hdeg = phora->tm_hour * 30 + mdeg * 0.0833333;
        hx = cos((hdeg - 90) * 0.0174532925);
        hy = sin((hdeg - 90) * 0.0174532925);
        lineReloj[0] = sf::Vertex(sf::Vector2f(LUGARX, LUGARY), sf::Color::Black);
        lineReloj[1] = sf::Vertex(sf::Vector2f(hx * 80 + LUGARX, hy * 80 + LUGARY), sf::Color::Black);
        ventana.draw(lineReloj, 2, sf::Lines);

        ventana.display();
    }

    while (ventana.pollEvent(evento)) {
        if (evento.type == sf::Event::Closed) {
        printf("Cerrando ventana SFML\n");
        ventana.close();
        }
     }

    }
}

Para dibujar el reloj debemos crear un círculo trasparente de 120 pilxes de diámetro , con una línea de 2 pilxes de ancha.
        sf::CircleShape circulo1(120);
        circulo1.setPosition(LUGARX - 120, LUGARY - 120);
        circulo1.setFillColor(sf::Color::Transparent);
        circulo1.setOutlineThickness(2);
        circulo1.setOutlineColor(sf::Color::Blue);
       
ventana.draw(circulo1);
Creamos líneas para cada 5 minutos, y líneas para cada aguja.
Los cálculos no son tema de este tutorial, por lo que solo explico la forma en que crea las líneas con la API SFML.
Creo la clase  sf::Vertex lineReloj[2] , que se utilizará para todas las líneas de reloj.
Para dibujar una línea se necisitan 2 punto, además del color con que queramos pintar la línea.
        lineReloj[0] = sf::Vertex(sf::Vector2f(x0, y0), sf::Color::Blue);
        lineReloj[1] = sf::Vertex(sf::Vector2f(x1, y1), sf::Color::Blue);

Ahora imprimimos la línea con
        ventana.draw(lineReloj, 2, sf::Lines);


Espero que este pequeño tutorial os solucione muchas dudas.

PROGRAMA

Saludos.
Juan Galaz