Mover formas simples en pantalla con C++ y SFML

Animación 2D con C++ y SFML. Un Circulo que se mueve en en pantalla.

En esta parte del curso vamos a hacer un programa que simule a una balón o pelota que rebote dentro de una ventana de  como se muestra en la siguiente animación:


                                                                        Figura 1

Pantalla de gráficos
Los gráficos en el mundo virtual se basa en píxeles . Un píxel es un pequeño punto en la pantalla que tiene una posición y sus valores se establecen con dos variables (coordenadas) como en matemáticas x ,y. El sistema de coordenadas en la pantalla de un computador u otro dispositivo está establecido como lo muestra la figura 2. La coordenada 0,0 esta en la esquina superior izquierda  y la coordenada superior, en la esquina inferior derecha. Por ejemplo en la figura 2 vemos representada una pantalla o ventana con una resolución 800x600 píxeles sobre la cual se ve dibujado un rectángulo de lados iguales en la coordenada 400,300 y un píxel en la coordenada 75,75.

                                                                            Figura 2

La ilusión del movimiento
Para dibujar el rectángulo en otro lugar de la pantalla o cambiar su posición simplemente se modifica sus coordenadas (x, y). Para crear la ilusión del movimiento del rectángulo en la pantalla, se borra el rectángulo anterior y luego se dibuja uno en la nueva posición bastante cerca. La estrategia en SFML es dibujar-borrar-dibujar y se repite indeterminadamente hasta conseguir cierta condición controlada por una sentencia while (mientra que). Ésta sentencia, ejecuta una sección de código mientras la condición dada sea verdadera, de lo contrario sale del bucle y continua con el código siguiente después del bloque while es decir después de la llave  '}' . Una condición while tiene la siguiente estructura

while (condición)


  sentencias

En los programas SFML de los ejemplos realizados en las entradas anteriores hay una sentencia de control principal while en cuyo cuerpo (cuerpo del while) se escriben todas las sentencias para dibujar. Dichas sentencias se ejecutan hasta que la condición dentro de los paréntesis sea falsa; es decir que hasta que la ventana es cerrada. Dicho bucle es el que vamos a utilizar para colocar todas nuestras sentencias, que en este caso van a realizar una animación de una figura como un circulo que emula una pelota o balón rebotando en la pantalla.

    while (ventana.isOpen())
    {
              1 Aquí escuchamos los eventos para captar cuando el usuario cierre la ventana

              2 Limpiamos la pantalla
         
              3 Cambiar los valores de las coordenadas x,y
         
             4 Pasamos las nuevas coordenadas x,y al objeto circulo
   
             5 Dibujamos en la ventana el circulo en la coordenada que recibió en la sentencia anterior
       
             6 Mostramos la ventana en la pantalla del computador
            }

Análisis y detalles del movimiento.
Básicamente  las sentencias anteriores son las que necesitamos para crear una animación de una figura simple en 2D. Pero antes de empezar a escribir el código vamos a analizar los detalles del movimiento de la figura en la pantalla.

Movimiento en linea recta y el rebote en los bordes de la ventana

Primero, vamos a crear una pantalla con un tamaño de 800 x 600 píxeles (ver figura 3). Ejemplo, si queremos desplazar  la figura desde la coordenada 0,0 hasta la coordenada  300,300 debemos incrementar equitativa y progresivamente los valores de x, y. Ahora, si seguimos incrementando los valores de x y y hasta que el valor de  x >=  800 o y >=  600 la pelota simplemente desaparece de la pantalla.

Incrementando de uno en uno a las coordenadas x y y es decir x = x + 1, y = y + 1 tenemos:
x = 0,1,2,3,4,...,600,601,602,...799,800....
y = 0,1,2,3,4,...,600,601,602,...799,800...

La figura desaparece de la ventana cuando y >= 600

Como vemos, el incremento tanto para x como para y es de 1. Si inicialmente la figura está en la coordenada (0,0) y el incremento de x y y al mismo tiempo es de +1 (pixel).

El desplazamiento de la figura es en linea recta diagonal hacia abajo. Cuando y es igual o mayor a 600  la figura empieza a estar fuera del rango de la ventana creada con un tamaño de 800x600 píxeles y empieza a desaparecer.

Para evitar que la figura se dibuje fuera de los limites del tamaño de la ventana, establecemos limites a su trayectoria y la encerramos en 4 paredes o bordes de la ventana establecida. Para ello usamos las sentencias de control que ofrece el lenguaje con las condiciones necesarias para cada limite:

izquierdo <=0.
derecho>=800.
arriba<=0.
abajo>=600.

Al cumplirse algunas de estas condiciones simplemente invertimos la dirección del objeto en movimiento, cambiando el signo del incremento de la variable correspondiente x o y, es decir, de +1 a -1 o de -1+1.

En C++ y en otros lenguajes de programación existen las sentencias de control como "if", que estable una condición,  que de ser cierta, ejecuta las instrucciones dentro del cuerpo de la condición, ejemplo:

         if (x <= pared_izq)
             xincremento = abs(xincremento);

        if (x >= pared_der)
            xincremento =-xincremento;

        if (y <= techo)
            yincremento = abs(yincremento);

        if (y >= piso)
            yincremento =-yincremento;

 El bloque de condiciones anteriores garantiza que la figura (pelota) se mantenga rebotando dentro de los limites establecido por los valores de las paredes, techo y piso.

Ahora hay dos detalles adicionales: primero, para convertir un numero positivo en negativo colocamos el signo menos (-) al lado del numero o variable (-xincremento) y  en segundo lugar para convertir un numero negativo en positivo usamos la función de valor absoluto abs(valor).

La trayectoria de la figura en una ventana de lados diferentes debe verse como la figura 3.

                                                                          Figura 3


Si la  ventana es de lados iguales la trayectoria de la figura será la misma ida vuelta como muestra la figura 4, ya que el limite de x y y son iguales si parte 0,0 y con incremento iguales para ambas variables.

Para que la trayectoria cambie, sólo basta con darle valores diferentes a los incrementos de las variables x, y. También a  medida que aumente el valor de incremento también aumenta la velocidad del movimiento de la figura.

                                                    Figura 4

Velocidad de los fotogramas
Hay un detalle técnico importante que hay que tomar en cuenta y es el control de la velocidad de los fotogramas, debido a que el ciclo de borrado y dibujo es tan rápido que probablemente no veamos nada en la pantalla. Para ello sincronizamos la frecuencia vertical del monitor que es aproximadamente 60 fotogramas por segundo. 

¿Como hacemos eso?, simplemente usamos las sentencias que proporciona SFML para tal fin y la escribimos justo después de crear la ventana:

ventana.setVerticalSyncEnabled(true);

otras veces necesitamos que se ejecute a velocidades diferentes y podemos usar la siguiente sentencia:

ventana.setFramerateLimit(30);


Si esta información te fue útil dale un plus +1, sigue este blog y así estas ayudando a que otros consigan la información compártela...


Ahora el código fuente completo
El código fuente (Versión 1.0 )

#include <SFML/Graphics.hpp>

int main()
{

    // creamos la ventana de 800x600 pixeles
    sf::RenderWindow ventana(sf::VideoMode(800, 600), "Ventana de Dibujo");
    // Definimos las variables
    int x = 1, y = 1;// coordenadas
    int incremento_x = 5, incremento_y = 5;
    int limite_izquierdo = 0, limite_derecho = 800;
    int limite_superior = 0, limite_inferior = 600;

    //creamos un objeto circulo con un radio 10
    // y definimos su color verde

    sf::CircleShape circulo1(10);
    circulo1.setFillColor(sf::Color::Green);

    // ejecutar el programa mientras la ventana esté abierta
    while (ventana.isOpen())
    {
        //verificamos todos los eventos de la ventana 
        sf::Event evento;
        while (ventana.pollEvent(evento))
        {
            // "cierre solicitado" evento: cerramos la ventana
            if (evento.type == sf::Event::Closed)
                ventana.close();
        }

        // limpiamos la ventana con el color negro
        ventana.clear(sf::Color::Black);

        // verificamos los bordes de la ventana y cambiamos
        // el signo de los incrementos 

        if (x <= limite_izquierdo) 
             incremento_x = abs(incremento_x);

        if (x >= limite_derecho)
            incremento_x =-incremento_x;

        if (y <= limite_superior)
            incremento_y = abs(incremento_y);

        if (y >= limite_inferior)
            incremento_y =- incremento_y;

        x = x + incremento_x;
        y = y + incremento_y;

    //pasamos las coordenadas actuales (x,y) al objeto circulo1

        circulo1.setPosition(x,y);

        // dibujamos el circulo en la ventana
        ventana.draw(circulo1);

        // mostramos ventana en la pantalla
        ventana.display();

    }

    return 0;
}

El código fuente (Versión 2.0)

A continuación una versión mejorada del código anterior, donde se utiliza  las funciones incorporadas en SFML como el mover (.move) y obtener posición (.getPosition()) :

//Programa en SFML Y C++ que mueve una forma simple en pantalla Version 2.0

#include <SFML/Graphics.hpp>

int main()
{
const int max_x = 800, max_y = 600, min_x = 0, min_y = 0;
float  r_ball = 10.f; //Radio del circulo
float  movx = 5.f, movy = 5.f; // incremento de las coordenada del circulo
float x = 0, y = 0; // coordenadas iniciales de ball

sf::RenderWindow window(sf::VideoMode(max_x, max_y), "@intellvirtual: Mover Formas Simples");
window.setVerticalSyncEnabled(true);// sincronismo vertical para reducir la velocidad de fotogramas
sf::CircleShape ball(r_ball);
ball.setFillColor(sf::Color::Yellow);
ball.setPosition(x, y);

while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}

sf::Vector2f posicion = ball.getPosition();//posición actual  del circulo
x = posicion.x; 
y = posicion.y;

if (x == max_x - r_ball * 2 || x < min_x)//r_ball*2 toma en cuenta el diámetro del circulo
movx *= -1;

if (y == max_y - r_ball * 2 || y < min_y)
movy *= -1;

ball.move(movx, movy);//mueve el circulo de su posición actual
//de  acuerdo al valores de incremento movx y movy    
window.clear();
window.draw(ball);
window.display();

}//window.isOpen
return 0;

}


😀Si te gusta nuestro blog suscríbete, coméntalo y comparte.👍
Nuestro equipo estará muy contento y compartirá mas contenido gratuito para tu aprendizaje.😉


Si quieres saber como realizar movimiento con el teclado sigue el siguiente link:
https://intelligenciavirtual.blogspot.com/2018/01/mover-formas-simples-en-pantalla-con-el.html




Comentarios

  1. Hace tiempo que buscaba este ejemplo. Gracias por compartir

    ResponderEliminar
  2. Muchas gracias, excelente aporte, un abrazo

    ResponderEliminar
  3. Respuestas
    1. Si te refieres a SFML, lo he podido probar en :

      codeblocks:
      https://intelligenciavirtual.blogspot.com/2014/09/instalar-codeblocks-en-windows.html

      Visual Studio:
      https://intelligenciavirtual.blogspot.com/2018/11/como-instalar-sfmf-25-en-visual-studio.html

      Linux:
      https://intelligenciavirtual.blogspot.com/2016/06/instalar-sfml-en-linux-debian.html



      Eliminar

Publicar un comentario

Entradas populares de este blog

Dibujar formas simples con C++ y SFML

Como Mover Formas Simples Con el Teclado con C++ y SFML