Paso a paso desarrollo de un videojuegos con C++ y SFML Parte I


Un videojuego sencillo  en C/C++ y SFML




Parte I
En la entrada animación 2D escribimos un programa muy sencillo que simulaba un circulo que rebotaba en los limites de la ventana que creamos en SFML como muestra la Pantalla 1 y el movimiento del circulo se ilustra en la parte izquierda de la figura A . Basado en el mismo principio y en el algoritmo convertimos en un programa, vamos a desarrollar un juego tipo Arkanoid muy sencillo en C++ y SFML conservando los limites derecho,superior e izquierdo,  como lo muestra la pantalla 1 y dejamos  el limite inferior o piso en control del usuario, para ello colocamos un pequeño rectángulo que el usuario puede mover hacia la derecha o izquierda y evitar que la pelota caiga al vacío como lo muestra la Pantalla 2 y la parte derecha de la figura A.

Pelota que rebota en pantalla by IntelligenciaVIrtual
                       Pantalla 1

Primeros pasos Diseño de VIdeoJuegos tipo Arkanoid By IntelligenciaVirtual
                                                                                                                            





    

 

Pantalla 2    

Movimiento del circulo o pelota

Como vemos en la Figura A el circulo se va a mover de manera autónoma entre los limites izquierdo-derecho-superior, incrementando o disminuyendo el valor de su coordenadas x, y dependiendo del limite donde se encuentre.

Primeros pasos Diseño de VIdeoJuegos tipo Arkanoid By IntelligenciaVirtual
Figura A
Las condiciones que establecimos para establecer el comportamiento de la pelota fueron dadas con las siguientes instrucciones:

if (x_cir <= limite_izq){
    incremento_x_cir = -1*(incremento_x_cir);
}

if (x_cir >= limite_der - (radio_cir*2)){

    incremento_x_cir =-incremento_x_cir;
}

if (y_cir <= limite_sup){

    incremento_y_cir = -1*(incremento_y_cir);
}


                                                                                                                   Figura B
Pantalla de Computadoras Primeros pasos Diseño de VIdeoJuegos tipo Arkanoid By IntelligenciaVirtual
Los valores de las variables incremento_x_cir  e incremento_y_cir determinan el sentido y la velocidad del circulo(pelota o balón). Por lo momentos, esa velocidad va ser fija, pero si queremos aumentar la dificultad del juego, podemos aumentarla a medida que se avance en los niveles del juego. En cuanto al sentido o dirección del circulo, cuando ambos valores del los incrementos de x , y son positivos (+) el circulo se desplaza hacia abajo y a la derecha, cuando incremento de y es negativo hacia abajo y a la derecha y cuando el incremento de x es negativo el movimiento es hacia la izquierda hacia arriba o abajo, en pocas palabras el signo del incremento de x determina la dirección horizontal y el signo del incremento de y determina el sentido vertical como vemos en el siguiente gráfico donde el valor del incremento es 1 (+1 o -1).


Movimiento del Rectángulo

En éste escenario que queremos crear, además del circulo en movimiento, debemos dibujar un rectángulo en la parte inferior de la ventana. El rectángulo o barra debe moverse a voluntad del usuario en sentido horizontal hacia la derecha o a la izquierda dentro de los limites derecho e izquierdo respondiendo a la orden de las teclas <-- o -->. 

Hasta el momento solo hemos hemos manejado el evento cuando se cierra la ventana. Ahora vamos a manejar los eventos del teclado que nos interesa para mover un rectángulo de acuerdo a los eventos del teclado. Para ello debemos tener presente los cuatro pasos siguientes

 Primero: debemos crear un objeto rectángulo

sf::RectangleShape barra(sf::Vector2f(largo_barra, altura_barra));

 Segundo: Le damos una acción a los eventos del teclado únicamente a las teclas derecha e izquierda.

if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
    if(x_rec <= limite_der - largo_barra){
       x_rec = x_rec + incremento_x_rec;
     }
}

if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {
    if(x_rec >= limite_izq){
       x_rec = x_rec - incremento_x_rec;
}

Tercero: teniendo las nuevas coordenadas del rectángulo se la pasamos al objeto rectángulo.

barra.setPosition(x_rec,y_rec);

Cuarto: se dibuja el rectángulo en la posición que fijamos con set.Position.

ventana.draw(barra);    // dibujamos el rectángulo en la ventana

Manejo de colisiones con SFML 

Colisión de circulo con la barra 

Hasta el momento las tres condiciones limites planteadas en el movimiento del circulo aplican para el limite izquierdo, el limite superior y el limite derecho. En limite inferior o piso, depende del jugador. Si el jugador ubica el rectángulo en la trayectoria del circulo antes de pasar el limite inferior, entonces la condición hace que cambie el sentido del incremento (+) de y, es decir incremento_y_cir a negativo (-), para que simule el rebote como se ve en la pantalla 2. Para cambiar el signo del valor del incremento simplemente lo multiplicamos por (-1).


 incremento_y_cir = -1*incremento_y_cir;

Para poder determinar si ambos objetos (circulo y rectángulo) se tocan debemos determinar si sus coordenadas se interceptan. La librería  SFML  ofrece soporte de colisiones que nos permite hacer el manejo de las mimas de una manera fácil e intuitiva. Lo primero que debemos hacer, es  crear las entidades rectangulares o cajas (ver figura C) para cada objeto al cual nos interesa manejar si se intercepta con otro. Dichas cajas encierra a cada objeto como se ve la figura.
Colisiones VIdeojuegos by IntelligenciaVIrtual
Figura C

Como vemos en ejemplo de la figura C tenemos un circulo con radio 5 y un rectángulo de 20 x 10. Las coordenadas del borde del circulo inicia en 160,220 y terminan en 170,230 y las del rectángulo inicia en 170,230 y terminan en 240,190. Ya creadas las cajas de cada objeto, SFML ofrece una función que determina si ambos rectángulos se interceptan.

Primero creamos las cajas rectangulares circulo1Box y barraBox que encierran al circulo y la barra utilizando el nombre del objeto que creamos:

sf::FloatRect circulo1Box = circulo1.getGlobalBounds();
sf::FloatRect barraBox    = barra.getGlobalBounds();

y luego podemos determinar si hay colisión con la siguiente función:

if (circulo1Box.intersects(barraBox)){

         // acciones de la colisión
    incremento_y_cir = -1* incremento_y_cir;//rebote
}

Ya tenemos nuestro cuarto limite si hay colisión entre el circulo y la barra hay rebote de lo contrario colocamos el circulo en la posición inicial para que empiece de nuevo.

Básicamente nuestro programa tiene que tener la siguiente estructura

 while (ventana.isOpen())
    {
              1 Aquí escuchamos los eventos:
                                1.1 Cerrar ventana,
                                1.2 Tecla pulsadas  < o >.

              2 Limpiamos la pantalla
       
              3 Cambiar los valores de las coordenadas x,y
       
              4 Pasamos las nuevas coordenadas x,y al objeto circulo y a la barra basada en evento 1.2

              5 Creamos las cajas borde de los objetos circulo y barra

              6 Verificamos si hay colisión:
                    6.1 si hay colisión pasamos el incremento de la coordenada y del circulo a negativo.
 
              6 Dibujamos en la ventana el circulo y la barra en la coordenada que recibió en el paso 4
     
               7 Mostramos la ventana en la pantalla
            }



A continuación el código fuente completo.

El código fuente (Version 1.0)


#include <SFML/Graphics.hpp>


int main()
{

    // creamos la ventana de 320x240 pixeles

    sf::RenderWindow ventana(sf::VideoMode(320, 240), "@intellvirtual");

  // sincronizamos la frecuencia de la ventana con la del monitor

    ventana.setVerticalSyncEnabled(true);

    int limite_izq = 0, limite_der = 320, limite_sup = 1, limite_inf = 240;

    int x_cir = 10, y_cir = 10, x_rec = 135, y_rec = 230;
    int incremento_x_cir = 1, incremento_y_cir = 1; // velocidad del circulo
    int incremento_x_rec = 15; // velocidad de triangulo
    int largo_barra = 50, altura_barra = 10;
    int radio_cir = 10;

    // definimos un circulo de radio = 10

    sf::CircleShape circulo1(radio_cir);
    // define una barra con un rectangulo largo = 50 , altura = 10
    sf::RectangleShape barra(sf::Vector2f(largo_barra, altura_barra));

    // 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();

        }

         // eventos del teclado
           if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
                if(x_rec <= limite_der - largo_barra){
                    x_rec = x_rec + incremento_x_rec;
                }
             }

             if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {

                if(x_rec >= limite_izq){
                     x_rec = x_rec - incremento_x_rec;
                }
             }

        // limpiamos la ventana con el color negro

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


        // verificamos los bordes de la ventana y cambiamos

        // el signo del incremento de x_cir,y_cir
        if (x_cir <= limite_izq){
             incremento_x_cir = -1*(incremento_x_cir);
        }
        if (x_cir >= limite_der - (radio_cir*2)){
            incremento_x_cir =-incremento_x_cir;
        }
        if (y_cir <= limite_sup){
           incremento_y_cir = -1*(incremento_y_cir);
        }

        if (y_cir >= limite_inf - (radio_cir*2)){// en el vacío!!! 

                x_cir = 10, y_cir = 10;     
        }

        x_cir = x_cir + incremento_x_cir;

        y_cir = y_cir + incremento_y_cir;

        //pasamos las nuevas coordenadas al objeto circulo1

        circulo1.setPosition(x_cir,y_cir);
        barra.setPosition(x_rec,y_rec);


        sf::FloatRect circulo1Box = circulo1.getGlobalBounds();

        sf::FloatRect barraBox = barra.getGlobalBounds();

         if (circulo1Box.intersects(barraBox)){//colision


            incremento_y_cir = -1* incremento_y_cir;
        }

        ventana.draw(circulo1);  // dibujamos el circulo en la ventana
        ventana.draw(barra);    // dibujamos el rectángulo en la ventana

        // mostramos ventana en la pantalla

        ventana.display();

    } // al cerrar la ventana salto esta llave


    return 0;//devuelvo el control al SO 

}

Comentarios

Entradas populares de este blog

Mover formas simples en pantalla con C++ y SFML

Dibujar formas simples con C++ y SFML

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