Paso a paso desarrollo de un videojuego con C++ y SFML Parte III
Mi primer videojuego C++ y SFML
Hasta los momentos hemos construido gran parte de nuestro videojuego.
Básicamente lo hemos realizado en varios pasos (Parte I + Parte II) y que vamos a resumir a continuación:
Parte I
Hasta los momentos hemos construido gran parte de nuestro videojuego.
Básicamente lo hemos realizado en varios pasos (Parte I + Parte II) y que vamos a resumir a continuación:
Parte I
1) Creamos una ventana de dibujo.
2) Dibujamos una figura en pantalla (Circulo)
3) Movemos el circulo en la pantalla cambiando sus coordenadas con circulo.setPosition(400, 300)
4) Mover el circulo repetidamente usando el bucle while de la ventana creada y utilizando variables para las coordenadas del circulo circulo.setPosition(x, y) incrementando los valores de x e y.
4.1) Establecer limites al movimiento del circulo con la condición if.
5) Mover el circulo con una variable de incremento que cambia de sentido con el signo (+ o -) y utilizar la condición if para establecer los limites superior, inferior, izquierdo y derecho.
6) Dibujar un rectángulo en la parte inferior.
7) Mover el rectángulo con el teclado (Usando las teclas A y D)
8) Eliminar el limite inferior y establecer el rectángulo como el limite manejando la colisión entre el circulo y el rectángulo.
Parte II
Parte II
9) Dibujar los cuadrado en la parte superior manualmente.
10) Dibujar cuadrado en la parte superior aplicando matemáticas y utilizando arrays.
Para simplificar he eliminado los limites laterales (derecho e izquierdo) de la barra inferior y hemos dejado el color por defecto de las figuras,
es importante concentrarnos mas en la mecánica del juego y mas adelante ocuparnos del diseño y la apariencia aspectos también muy importantes.
Código fuente Parte I y Parte II
es importante concentrarnos mas en la mecánica del juego y mas adelante ocuparnos del diseño y la apariencia aspectos también muy importantes.
Código fuente Parte I y Parte II
#include <SFML/Graphics.hpp> |
int main() |
{ |
|
int x_min = 0 ,x_max = 800; |
int y_min = 0 ,y_max = 600; |
|
sf::RenderWindow ventana(sf::VideoMode(x_max,y_max),"IntelligenciaVirtual"); |
|
//Circulo-Pelota |
int xc = 0, yc = 0 , rc=10; |
int incre_xc = 1, incre_yc = 1; //incremento de variables |
sf::CircleShape circulo(rc); // (rc= radiodel circulo) |
|
// Rectángulo-Barra |
int lr = 100, ar = 20; |
int incre_xr = 10, incre_yr = 10; |
int xr = (x_max-lr)/2 , yr = y_max - ar; |
sf::RectangleShape rectangulo(sf::Vector2f(lr, ar)); |
|
// cuadrados-ladrillos |
int const n = 20;// Cantidad de cuadrados |
int ls = (4 * x_max) / (5 * n);// ecuación calcula el ancho de cuadrado para una separación = ls/4 |
int xs = 0 , ys = 0; //posición inicial de los cuadrados |
sf::RectangleShape cuadrados[n]={};// array de cuadrados |
|
for (int i = 0; i < n; ++i)//creamos n cuadrados y lo guardamos en un array |
{ |
cuadrados[i] = sf::RectangleShape (sf::Vector2f(ls, ls)); //creamos n cuadrados y lo guardamos en un array |
} |
|
while (ventana.isOpen()) |
{ |
sf::Event event; |
while (ventana.pollEvent(event)) |
{ |
if(event.type == sf::Event::Closed) |
ventana.close(); |
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) |
xr += incre_xr; |
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) |
xr -= incre_xr; |
} |
|
ventana.clear(); //Limpiamos La Ventana |
|
//Aquí cambiamos la posición de los objetos |
|
if (xc > x_max-rc*2 || xc < x_min) |
incre_xc = -incre_xc; |
if (yc > y_max-rc*2) |
xc = yc = 0; |
if (yc < y_min) |
incre_yc = -incre_yc; |
|
xc += incre_xc; // equivale a xc = xc + incre_xc |
yc += incre_yc; |
|
circulo.setPosition(xc,yc); |
rectangulo.setPosition(xr,yr); |
|
//Cajas de colisión |
sf::FloatRect circuloBox = circulo.getGlobalBounds(); |
sf::FloatRect rectanguloBox = rectangulo.getGlobalBounds(); |
|
//detectando la colisión del circulo con el rectángulo |
if (circuloBox.intersects(rectanguloBox)){ |
incre_yc = -incre_yc; |
} |
|
//Aquí dibujamos |
for(int i = 0; i < n; ++i){ |
xs = i * (ls + ls/4 ); |
cuadrados[i].setPosition(xs,ys); |
ventana.draw(cuadrados[i]); |
} |
|
ventana.draw(circulo); |
ventana.draw(rectangulo); |
ventana.display(); //Mostramos el Contenido de la Ventana |
} |
|
El resultado del código fuente desarrollado en la parte I y II debe darte como resultado algo parecido a la siguiente imagen. En en código establecimos que para mover la barra inferior que hace rebotar a la pelota se debe utiliza las teclas A (izquierda) y D (derecha).
Parte III Destruir los cuadrados cuando es tocado por el circulo.
Como vemos la pelota representada por un circulo solo rebota en lo limites de la ventana y no con cada cuadrado y en la parte inferior, sólo cuando colisiona con la barra controlada por el jugador. Hasta ahora no hemos manejado la colisión con cada ladrillo que son representado con un cuadrado.
Para lograr que nuestra pelota destruya cada ladrillo debemos hacer algo similar a lo realizado con la barra y el circulo; debemos crear una caja de bordes para cada cuadrado, es decir para cada uno de los cuadrados almacenados en cuadrado[i] donde i representa el índice de cada cuadrado que va desde 0 hasta n.
Ahora además del array de cuadrado que creamos con la siguiente sentencia:
sf::RectangleShape cuadrados[n];// array de cuadrados
debemos crear un array de cajas de bordes para guardar el área de cada cuadrado
sf::FloatRect cuadradosBox[n];// array de caja de colisiones
para aprovecha el bloque del dibujo de cada cuadrado en la parte del código que dice //aquí dibujamos vamos a guardar el borde de cada cuadrado[i] en cuadradoBox[i]
//Aquí dibujamos
for(int i = 0; i < n; ++i){
xs = i * (ls + ls/4 );
cuadrados[i].setPosition(xs,ys);
cuadradosBox[i] = cuadrados[i].getGlobalBounds();
ventana.draw(cuadrados[i]);
}
y finalmente similar a la detección de la colisión del circulo con el rectángulo usamos una condición if para detectar la colisión del circulo con cada cuadrado recorriendo todo el array con la sentencia de control for.
//colisión del círculo con cada cuadrado
for (int i = 0; i < n; ++i){
if (circuloBox.intersects(cuadradosBox[i])){
incre_yc = -incre_yc;// incremento de la variable "y" del circulo
}
}
agregando los fragmentos de código en colo azul al código completo desarrollado en la parte I y II obtendremos un resultado igual al que muestra la siguiente imagen.
se puede observar a diferencia de la imagen anterior, el circulo al tocar un cuadrado rebota, y ese es el resultado que queremos por lo momentos. El siguiente paso es agregar las sentencias necesarias para destruir los cuadrados que toque el circulo. Daremos todo el detalle necesarios y el código fuente completo.
En este enlace encontraras el código fuente para obtener el resultado de la imagen anterior.
Ya teniendo el control de la colisión del circulo con cada cuadrado el siguiente paso es destruir el cuadrado. Para ello vamos a darle valor a cada cuadrado el valor uno "1" cuando esta activo y cero "0" cuando esta destruido. Es decir cada cuadrado va a tener dos estados "0" (vivo) o "1" (muerto). Para almacenar el estado de cada cuadrado utilizamos un arreglo (array) de estado de cuadrados y lo declaramos de la siguiente manera:
// cuadrados
int estadocuadrado[n]={};
y dentro de bucle for que usamos para crear y almacenar cada cuadrado al mismo tiempo se inicializa su valor en 1.
for(int i = 0; i < n; ++i){
Para lograr que nuestra pelota destruya cada ladrillo debemos hacer algo similar a lo realizado con la barra y el circulo; debemos crear una caja de bordes para cada cuadrado, es decir para cada uno de los cuadrados almacenados en cuadrado[i] donde i representa el índice de cada cuadrado que va desde 0 hasta n.
Ahora además del array de cuadrado que creamos con la siguiente sentencia:
sf::RectangleShape cuadrados[n];// array de cuadrados
debemos crear un array de cajas de bordes para guardar el área de cada cuadrado
sf::FloatRect cuadradosBox[n];// array de caja de colisiones
para aprovecha el bloque del dibujo de cada cuadrado en la parte del código que dice //aquí dibujamos vamos a guardar el borde de cada cuadrado[i] en cuadradoBox[i]
//Aquí dibujamos
for(int i = 0; i < n; ++i){
xs = i * (ls + ls/4 );
cuadrados[i].setPosition(xs,ys);
cuadradosBox[i] = cuadrados[i].getGlobalBounds();
ventana.draw(cuadrados[i]);
}
y finalmente similar a la detección de la colisión del circulo con el rectángulo usamos una condición if para detectar la colisión del circulo con cada cuadrado recorriendo todo el array con la sentencia de control for.
//colisión del círculo con cada cuadrado
for (int i = 0; i < n; ++i){
if (circuloBox.intersects(cuadradosBox[i])){
incre_yc = -incre_yc;// incremento de la variable "y" del circulo
}
}
se puede observar a diferencia de la imagen anterior, el circulo al tocar un cuadrado rebota, y ese es el resultado que queremos por lo momentos. El siguiente paso es agregar las sentencias necesarias para destruir los cuadrados que toque el circulo. Daremos todo el detalle necesarios y el código fuente completo.
En este enlace encontraras el código fuente para obtener el resultado de la imagen anterior.
Ya teniendo el control de la colisión del circulo con cada cuadrado el siguiente paso es destruir el cuadrado. Para ello vamos a darle valor a cada cuadrado el valor uno "1" cuando esta activo y cero "0" cuando esta destruido. Es decir cada cuadrado va a tener dos estados "0" (vivo) o "1" (muerto). Para almacenar el estado de cada cuadrado utilizamos un arreglo (array) de estado de cuadrados y lo declaramos de la siguiente manera:
// cuadrados
int estadocuadrado[n]={};
y dentro de bucle for que usamos para crear y almacenar cada cuadrado al mismo tiempo se inicializa su valor en 1.
for(int i = 0; i < n; ++i){
cuadrados[i] = sf::RectangleShape (sf::Vector2f(ls, ls));
estadocuadrado[i] = 1;
}
A continuacion el codigo fuente completo:
Esto quiere decir que todos los cuadrados inician todos prendidos. Cuando el circulo toca por primera vez a un cuadrado es decir hay una intersección entre sus coordenadas y su estado es 1 e inmediatamente debe pasar a estado 0.
Si el circulo vuelve a pasar por donde estaba un cuadrado que está en estado 0 no debe haber colisión y debe rebota en el borde superior de la ventana. Debemos asegurar que para que pueda haber una colisión debe cumplirse dos condiciones: la primera es que debe haber una intersección y la segunda es que el estado del cuadrado debe ser igual a 1. Traducido en lenguaje C++ es:
//manejo de colisiones del circulo con los cuadrados
for (int i = 0; i < n; ++i){
if (circuloBox.intersects(cuadradosBox[i]) && estadocuadrado[i] == 1){
incre_yc = -incre_yc;
estadocuadrado[i] = 0;
if (circuloBox.intersects(cuadradosBox[i]) && estadocuadrado[i] == 1){
incre_yc = -incre_yc;
estadocuadrado[i] = 0;
}
}
y si un cuadrado esta en estado = 0, debemos asegurarnos de no dibujarlo en pantalla
//Aqui dibujamos
for(int i = 0; i < n; ++i){
xs = i * (ls + ls/4 );
cuadrados[i].setPosition(xs,ys);
if (estadocuadrado[i] == 1){
ventana.draw(cuadrados[i]);
}
xs = i * (ls + ls/4 );
cuadrados[i].setPosition(xs,ys);
if (estadocuadrado[i] == 1){
ventana.draw(cuadrados[i]);
}
}
A continuacion el codigo fuente completo:
#include <iostream> | ||||
#include <SFML/Graphics.hpp> |
int main() |
{ |
int x_min = 0 ,x_max = 800; |
int y_min = 0 ,y_max = 600; |
sf::RenderWindow ventana(sf::VideoMode(x_max,y_max),"Parte III Intelligencia Virtual"); |
|
//Circulo |
int xc = 50, yc = 50 , rc=10; |
int incre_xc = 1, incre_yc = 1; //incremeto de variables |
sf::CircleShape circulo(rc); // (rc= radiodel circulo) |
|
// Rectangulo |
int lr = 100, ar = 20; |
int incre_xr = 10, incre_yr = 10; |
int xr = (x_max-lr)/2 , yr = y_max - ar; |
sf::RectangleShape rectangulo(sf::Vector2f(lr, ar)); |
|
// cuadrados |
int const n = 20;// Cantidad de cuadrados |
int ls = (4 * x_max) / (5 * n);// ecuacion calcula el ancho de cuadrado para una separacion = ls/4 |
int xs = 0 , ys = 0; //posicion inicial de los cuadrados |
sf::RectangleShape cuadrados[n];// array de cuadrados |
sf::FloatRect cuadradosBox[n];// array de caja de colisiones |
for (int i = 0; i < n; ++i){//creamos n cuadrados y lo guardamos en un array |
cuadrados[i] = sf::RectangleShape (sf::Vector2f(ls, ls)); //creamos n cuadrados y lo guardamos en un array |
} |
|
while (ventana.isOpen()) |
{ |
sf::Event event; |
|
while (ventana.pollEvent(event)) |
{ |
if(event.type == sf::Event::Closed) |
ventana.close(); |
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) |
xr += incre_xr; |
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) |
xr -= incre_xr; |
} |
ventana.clear(); //Limpiamos La Ventana |
|
//Aqui cambiamos la posicion de los objetos |
if (xc > x_max-rc*2 || xc < x_min) |
incre_xc = -incre_xc; |
|
if (yc > y_max-rc*2) // cambio en paso 8 |
xc = yc = 50; |
|
if (yc < y_min) |
incre_yc = -incre_yc; |
|
xc += incre_xc; // equivale a xc = xc + incre_xc |
yc += incre_yc; |
|
circulo.setPosition(xc,yc); |
rectangulo.setPosition(xr,yr); |
|
//Cajas de colision |
sf::FloatRect circuloBox = circulo.getGlobalBounds(); |
sf::FloatRect rectanguloBox = rectangulo.getGlobalBounds(); |
|
//detectando la colision del circulocon el rectangulo |
if (circuloBox.intersects(rectanguloBox)){ |
incre_yc = -incre_yc; |
} |
|
//colision del circulo con cada cuadrado |
for (int i = 0; i < n; ++i){ |
|
if (circuloBox.intersects(cuadradosBox[i])){ |
incre_yc = -incre_yc; |
} |
} |
|
//Aqui dibujamos |
for(int i = 0; i < n; ++i){ |
xs = i * (ls + ls/4 ); |
cuadrados[i].setPosition(xs,ys); |
cuadradosBox[i] = cuadrados[i].getGlobalBounds(); |
ventana.draw(cuadrados[i]); |
} |
|
ventana.draw(circulo); |
ventana.draw(rectangulo); |
|
ventana.display(); //Mostramos el Contenido de la Ventana |
} |
} |
Comentarios
Publicar un comentario