Mover formas simples en pantalla con C++ y SFML
Animación 2D con C++ y SFML. Un Circulo que se mueve en en pantalla.
Pantalla de gráficos
Figura 2
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
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.
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 a +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.
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 a +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;
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:
¿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 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
//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
Hace tiempo que buscaba este ejemplo. Gracias por compartir
ResponderEliminarMuchas gracias, excelente aporte, un abrazo
ResponderEliminarFunciona para turbp c++?
ResponderEliminarSi te refieres a SFML, lo he podido probar en :
Eliminarcodeblocks:
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