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


Movimiento Por Teclado







En una entrada anterior vimos una introducción al movimiento autónomo de formas en la pantalla . También explicamos en detalle como está conformada la pantalla y sus coordenadas.

Si te interesa te recomiendo su lectura  antes de continuar:

Mover Formas Simples En Pantalla




En esta entrada vamos aprender algunas funciones elementales de SFML que nos permita  mover una figura en pantalla con el teclado.

Básicamente lo que queremos lograr es dibujar una figura con forma de triangulo, la cual podemos imaginar que es una nave espacial. 

La posición inicial de la nave puede ser  centro de la ventana, y luego, podrá desplazarse en pantalla en la dirección en  la cual, el usuario ordene con el teclado. 

Los movimientos de la nave estarán limitados a cuatro movimientos básicos: arriba, abajo, derecha e izquierda, y mas adelante veremos que al presionar dos teclas al mismo tiempo, como por ejemplo, arriba y derecha, se puede lograr un desplazamiento diagonal.

Para lograr nuestro objetivo, debemos darle a nuestro programa las funciones para que escuche constantemente las ordenes del teclado, es decir, manejar los eventos. Las Librerías de SFML vienen equipadas con rutinas para el manejo de eventos del teclado .

A continuación se describirá detalladamente en seis pasos un programa básico que te permita mover figuras en pantalla con el teclado.

  1- Primero: Crear la nave

SFML proporciona un conjunto de clases para representar figuras básicas como  el rectángulo, el circulo, y el triangulo. Esas clases también manejan la posición de las figuras, su tamaño, color, y texturas de la figura. 

Para ilustrar nuestro ejemplo vamos a crear un triangulo al cual vamos a llamar nave.

sf::CircleShape nave(15,3)

La sentencia anterior es interesante, ya que deducimos que por su nombre debería dibujar un circulo pero en realidad esta dibujando es un polígono de tres lados, como lo determina el segundo parámetro con el valor de tres (3) y el primer parámetro determina el tamaño del radio de la circunferencia en este ejemplo es 15.

  2- Segundo: Establecer una posición inicial a la nave

Le damos una posición lo mas centrada posible en la pantalla dividiendo entre dos el ancho y alto de la ventana creada.

int x_coord = ancho_ventana / 2 , y_coord = alto_ventana / 2;
nave.setPosition(x_coord, y_coord)

   3- Tercero: Darle el control de la nave al usuario
  Ahora programamos las teclas que le cambiara la dirección de la nave, y para lograrlo establecemos la         acción  que se desencadena al presionar una tecla determinada.
 Esta parte del código la ubicamos donde nuestro programa establece la comunicación con el mundo   externo, y lo llamamos escuchar los eventos.

 Por ahora vamos a limitar los eventos. Vamos a programar la nave para que sólo se mueva a:  derecha, izquierda, arriba y abajo:

if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
       x_coord  += 10;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
       x_coord  -= 10;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
       y_coord  -= 10;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
       y_coord  += 10;
Como vemos, dependiendo de la tecla presionada se incrementa o disminuye
el valor de las variables que representan las coordenadas de la nave  x_coord,y_coord.

Si presionamos dos teclas al mismo tiempo los valores cambian alternando entre x_coord y y_coord, y esto nos permite lograr el movimiento diagonal.

Observemos también que cuando presionamos arriba (Up) reducimos el valor de la variable "y", que difiere a lo que aprendemos en el sistema cartesiano en matemáticas ya que en una computadora es inverso la representación gráfica.

4- Cuarto: Actualizar las coordenadas de la nave

Cada vez que se presiona alguna de las teclas de dirección cambia los valores de las variables x_coord, y_coord . Esos valores deben ser pasados al objeto nave  para que actualice su posición, y lo hacemos con la siguiente instrucción:

nave.setPosition(x_coord ,y_coord);

5- Quinto: Actualizar el escenario antes de subir el telón

  Ya el objeto nave tiene sus nuevas coordenadas con set.Position, ahora procedemos a borrar todo lo que hay en la ventana (es decir la nave en su posición anterior ) y luego, dibujamos la nave en su nueva posición.

ventana.clear();    

ventana.draw(nave); // dibujamos la figura en la ventana buffer

6- Sexto: Mostrar al usuario como la nave se desplaza en la pantalla

Hasta el momento  no hemos mostrado aun la nave espacial en su nueva posición, para ello debemos dar la instrucción para que el escenario (ventana) se muestre en la pantalla con su nuevos cambios:

ventana.display();     // Mostramos la ventana en la pantalla
  
Podemos imaginar que los procesos de borrar, dibujar  y mostrar pasan constantemente al igual como lo hacen los fotogramas de una película, donde el director eres tu.

 Código fuente completo del ejercicio manejando eventos del teclado

//Codigo Fuente Movimiento por teclado SFML y C++ Version 0
#include <SFML/Graphics.hpp>
int main()
{
    int ancho_ventana = 214 , alto_ventana = 326; //tamaño de la ventana
    int x_coord = ancho_ventana / 2;

     int y_coord = alto_ventana / 2; //coordenadas iniciales de figura (triangulo)
    sf::RenderWindow ventana(sf::VideoMode(ancho_ventana, alto_ventana), "IntellVirtual!");

    sf::CircleShape nave(15,3);
    nave.setPosition(x_coord, y_coord);
    nave.setFillColor(sf::Color::Blue);
    while (ventana.isOpen())
    {
        sf::Event event;
        while (ventana.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                ventana.close();
         }

//eventos del teclado
         if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
              x_coord  += 10;
          if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
              x_coord  -= 10;
          if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
             y_coord  -= 10;
          if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
             y_coord  += 10;

    ventana.clear();
    nave.setPosition(x_coord, y_coord); //cambia la posición de la nave por el evento de teclado
    ventana.draw(nave);
    ventana.display();   
    }
return 0;
}



Problema: la figura se sale de la ventana

 Al compilar y ejecutar el programa anterior podremos ver que la nave puede sobrepasar  los limites de la ventana al usar la teclas configuradas en la estructura de control if.

Para establecer limites, sólo hay que agregar una condición adicional en la parte donde incrementamos los valores de las coordenadas x_coord y y_coord.

Esto mantendrá la nave dentro el espacio creado. Como veremos en los limites derecho y abajo, si no tomamos en cuenta el tamaño de la nave, la misma  se saldrá un poco de los limites. En el programa siguiente se agrega el tamaño de la nave como una variable para dicho fin.


       if ((sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) && (x_coord < ancho_ventana - radio_nave*2))
              x_coord  += 10;
        if ((sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) && (x_coord > 0 ))
              x_coord  -= 10;
        if ((sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) && (y_coord > 0))
          y_coord  -= 10;

        if ((sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) && (y_coord < alto_ventana - radio_nave *2))
        y_coord  += 10;

Código fuente completo del ejercicio manejando eventos del teclado y limitando el movimiento de la figura dentro de la ventana
// Programa que dibuja una figura en el centro de la pantalla y se mueve por teclado
//Codigo Fuente Movimiento por teclado SFML y C++ Version 0.5
 #include <SFML/Graphics.hpp>

int main()
{
    int ancho_ventana = 214 , alto_ventana = 326; //tamaño de la ventana
    int x_coord = ancho_ventana / 2;
//coordenada x inicial de figura (triangulo)

    int y_coord = alto_ventana / 2; //coordenada y inicial de figura (triangulo)
    int radio_nave = 15;
    sf::RenderWindow ventana(sf::VideoMode(ancho_ventana, alto_ventana), "IntellVirtual!");

    sf::CircleShape nave(radio_nave,3);
    nave.setPosition(x_coord, y_coord);
    nave.setFillColor(sf::Color::Blue);
    while (ventana.isOpen())
    {
        sf::Event event;
        while (ventana.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                ventana.close();

        }
//eventos del teclado
      if ((sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) && (x_coord < ancho_ventana - radio_nave *2))
               x_coord  += 10;
        if ((sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) && (x_coord > 0 ))
               x_coord  -= 10;
        if ((sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) && (y_coord > 0))
               y_coord  -= 10;     
        if ((sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) && (y_coord < alto_ventana - radio_nave*2))
                y_coord  += 10;
    ventana.clear();
    nave.setPosition(x_coord, y_coord); //cambia la posición de la figura por el evento de teclado
    ventana.draw(nave);
    ventana.display();    

    }
return 0;
}


El siguiente paso es optimizar el código utilizando las funciones de que proporciona
la biblioteca de SFML como move, para mover las entidades y getPosition para obtener
la posición actual de los objetos en la ventana. Incremente el tamaño de la ventana y ahora
se puede usar las teclas A,D,W,S para mover a la nave.

//Codigo Fuente Movimiento por teclado SFML y C++ Version 1.0
#include <SFML/Graphics.hpp>

int main()
{
   float x_min = 0.f, x_max = 512.f , y_min = 0.f, y_max = 512.f; //tamaño de la ventana
   float x_nave = x_max / 2; //coordenada x inicial de figura (triangulo)
   float y_nave = y_max / 2; //coordenada y inicial de figura (triangulo)
   float  radio_nave = 21.f;
   float x_mov_nave = 10.f, y_mov_nave = 10.f;//incremento de coordenadas o velocidad de la nave
   
   sf::RenderWindow ventana(sf::VideoMode(x_max, y_max), "@IntellVirtual!");
   ventana.setVerticalSyncEnabled(true);
   
   sf::CircleShape nave(radio_nave,3);
   nave.setPosition(x_nave, y_nave);
   nave.setFillColor(sf::Color::Blue);

   while (ventana.isOpen())
   {

       sf::Event event;

       while (ventana.pollEvent(event))
       {
           if (event.type == sf::Event::Closed)
               ventana.close();
      }
sf::Vector2f posicion_nave = nave.getPosition();//posicion actual  de la nave
x_nave = posicion_nave.x;
y_nave = posicion_nave.y;

// mueve la nave dentro de los limites de la ventana con las teclas A,D,W,S y las flechas
if ((sf::Keyboard::isKeyPressed(sf::Keyboard::Right) ||
    (sf::Keyboard::isKeyPressed(sf::Keyboard::D)))   && x_nave < x_max - radio_nave *2)
    nave.move(x_mov_nave,0.f);
if ((sf::Keyboard::isKeyPressed(sf::Keyboard::Left) ||
    (sf::Keyboard::isKeyPressed(sf::Keyboard::A)))  && x_nave > x_min)
    nave.move(-x_mov_nave,0.f);
if ((sf::Keyboard::isKeyPressed(sf::Keyboard::Up)   ||
     (sf::Keyboard::isKeyPressed(sf::Keyboard::W)))  && y_nave > y_min)
     nave.move(0.f,-y_mov_nave);
if ((sf::Keyboard::isKeyPressed(sf::Keyboard::Down) ||
    (sf::Keyboard::isKeyPressed(sf::Keyboard::S)))  && y_nave < y_max - radio_nave *2)
    nave.move(0.f,y_mov_nave);
   ventana.clear();
   ventana.draw(nave);
   ventana.display();    
   }
   
return 0;
}


Esta versión es un poco más clara y compacta que la anterior. Podemos controlar
el movimiento de nuestra nave con el teclado en varias direcciones. Ahora el paso
siguiente es agregar la función de disparar que lo publicaremos en una próxima entrada.
😀Si te gusta nuestro blog suscríbete, coméntalo y comparte.👍
Nuestro equipo estará muy contento y compartirá mas contenido gratuito para tu aprendizaje.😉



Comentarios

  1. Cuando cambias de dirección se produce una pausa muy molesta, es posible eliminar esa pausa?

    ResponderEliminar
  2. como podria mover sprites co el mouse?

    ResponderEliminar

Publicar un comentario

Entradas populares de este blog

Mover formas simples en pantalla con C++ y SFML

Dibujar formas simples con C++ y SFML