Bienvenidos sean a este post, hoy veremos como aplicar otro de los pilares fundamentales en OOP.
Lo que intentaremos es obtener una referencia de un objeto a traves de un puntero a nuestra clase base. Puede no sonar muy util pero esto nos permitira hacer que Juego pueda almacenar un listado de punteros para un tipo y todos los herederos de la misma dandonos tambien la posibilidad de poder agregar todos los que sean necesarios.
Pero para ello, necesitaremos el codigo del post anterior. Sino lo poseen les dejo un link para descargarlo:
Descarguen el archivo y extraigan el contenido en el PC. Lo unico que deben hacer es revincular a SDL y SDL_Image. Para ello, les recomiendo este post donde comento como hacerlo para SDL y este otro post donde hago lo mismo para SDL_Image. Una vez que este todo funcionando correctamente, podemos continuar. Lo siguiente sera implementar a polimorfismo, y para ello vamos a modificar primero a nuestra clase ObjetoJuego. Para esto, iremos al archivo de encabezado, ObjetoJuego.h, donde cambiaremos la parte publica de la siguiente manera:
public:
virtual void cargar(float, float, float, float, std::string);
virtual void dibujar(SDL_Renderer*);
virtual void actualizar();
virtual void limpiar();
Basicamente lo que hicimos fue transformar a todas las funciones en virtuales, el resto no modificamos nada ni tampoco modificamos las variables y objetos de la parte protegida.
Nuestra siguiente modificacion sera en la clase Juego, donde iremos al archivo de encabezado y en la parte privada de la clase, buscaremos a las siguientes lineas:
ObjetoJuego m_obj;
Jugador m_jugador;
Y lo modificaremos de la siguiente manera:
ObjetoJuego* m_obj;
Jugador* m_jugador;
Lo unico que hacemos es cambiar a un puntero los dos objetos creados. Luego agregaremos la siguiente declaracion despues de las dos anteriores:
std::vector<ObjetoJuego*> m_objetosJuego;
Esta se encargara de crear una variante de array que se ajusta de forma dinamica y permite objetos, la cual se encargara de contener los punteros de los objetos de tipo ObjetoJuego y hara lo que hablamos al principio. Nuestra siguiente modificacion sera en la funcion iniciar de Juego.cpp.
Nota:
Para habilitar a vector debemos agregar entre los include a #include <vector>
En la funcion iniciar, primero eliminaremos o comentaremos las siguientes dos lineas (les recomiendo comentar):
m_obj.cargar(100, 100, 128, 82, "animado");
m_jugador.cargar(300, 300, 128, 82, "animado");
Estas son las encargadas de cargar los datos de nuestros objetos, una vez eliminadas o comentadas procedemos a agregar las siguientes lineas:
m_obj = new ObjetoJuego();
m_obj->cargar(100, 100, 128, 82, "animado");
m_objetosJuego.push_back(m_obj);
m_jugador = new Jugador();
m_jugador->cargar(300, 300, 128, 82, "animado");
m_objetosJuego.push_back(m_jugador);
En este bloque podemos ver como se genera los dos objetos por medio de los constructores. Luego utilizamos la funcion cargar de cada una de ellos para pasar los datos para su creacion correcta y por ultimo mediante push_back los agregamos en nuestro array/vector llamado m_objetosJuego. Tecnicamente, ya tenemos nuestro array con un par de objetos. Pasemos a la siguiente modificacion en nuestra funcion renderizar, la cual modificaremos de la siguiente manera:
void Juego::renderizar() {
SDL_RenderClear(m_pRenderer);
for (std::vector<ObjetoJuego*>::size_type i = 0;
i != m_objetosJuego.size(); i++) {
m_objetosJuego[i]->dibujar(m_pRenderer);
}
SDL_RenderPresent(m_pRenderer);
actualizar();
}
Basicamente, lo que hicimos fue reemplazar a las dos lineas que usabamos para dibujar por un bucle que pasara por todos los elementos del array. La variable usada como iterador sera definida por size_type de la clase vector, y este sera igual al de nuestro array. Observen que pasara por todos los elementos y llamara a dibujar, la ventaja de trabajar de esta forma es que dibujara a todos los elementos por igual ya sean un objeto, el jugador o un enemigo. Con esto concluido, podemos pasar a nuestra siguiente modificacion que sera en la funcion actualizar la cual modificaremos de la siguiente manera:
void Juego::actualizar(){
for (std::vector<ObjetoJuego*>::size_type i = 0;
i != m_objetosJuego.size(); i++) {
m_objetosJuego[i]->actualizar();
}
}
Volvemos a repetir el bucle de la funcion renderizar pero en lugar de dibujar lo actualizaremos mediante actualizar. Una vez hecho, probemos de compilarlo y ver que sucede; deberan tener el mismo resultado que antes como se ve en el siguiente video
Vamos a hacer la ultima modificacion, para este caso vamos a crear una nueva clase a la cual llamaremos Enemigo con el mismo procedimiento para generarlos. Una vez creada la clase iremos a su archivo de encabezado y le agregaremos el siguiente codigo:
Enemigo.h
#pragma once
#ifndef __Enemigo__
#define __Enemigo__
#include "ObjetoJuego.h"
class Enemigo : public ObjetoJuego
{
public:
void cargar(float, float, float, float, std::string);
void dibujar(SDL_Renderer*);
void actualizar();
void limpiar();
};
#endif // !__Enemigo__
Como pueden observar es igual a la clase Jugador, salvo por el nombre identificador pero el resto es lo mismo. Lo siguiente es modificar a Enemigo.cpp donde definiremos a los prototipos que agregamos anteriormente. Para ello, agregaremos el siguiente codigo:
Enemigo.cpp
#include "Enemigo.h"
void Enemigo::cargar(float x, float y, float ancho, float alto,
std::string idTextura) {
ObjetoJuego::cargar(x, y, ancho, alto, idTextura);
}
void Enemigo::dibujar(SDL_Renderer* pRenderer) {
ObjetoJuego::dibujar(pRenderer);
}
void Enemigo::actualizar() {
m_x += 1;
m_y += 1;
}
void Enemigo::limpiar() {}
La funcion cargar, dibujar y limpiar son exactamente las mismas a Jugador pero actualizar va a ser la unica distint. En este caso, incrementaremos a los ejes X e Y y volvemos a actualizar al cuadro actual tal como hicimos anteriormente en este post. Nuestro ultimo paso antes de volver a probar el juego es modificar a Juego.h para agregar un nuevo objeto de tipo Enemigo pero primero incluiremos a la nueva clase:
#include "Enemigo.h"
Nuestro siguiente paso sera generar el objeto en el archivo de encabezado mas exactamente en la parte protegida:
Enemigo* m_enemigo;
Con esto declaramos nuestro nuevo objeto, lo siguiente sera ir a la funcion iniciar en la clase Juego y agregaremos las siguientes tres lineas:
m_enemigo = new Enemigo();
m_enemigo->cargar(0, 0, 128, 82, "animado");
m_objetosJuego.push_back(m_enemigo);
En estas lineas primero definiremos al nuevo objeto, luego cargaremos sus datos y por ultimo lo agregaremos dentro del array de nuestros objetos, compilamos y veamos como funciona mediante el siguiente video
Ene ste caso podemos contemplar como con minimas modificaciones podemos crear todos los objetos que queramos, crear sus respectivos punteros, meterlos dentro de un array/vector y poder manejarlos desde ahi sin necesidad de tener que hacer tantas modificaciones en nuestro codigo.
En resumen, hoy hemos aplicado polimorfismo para lograr tener en un array todos los objetos de nuestro juego, en realidad punnteros a dichos objetos pero con una funcion que permitira pasar por todos los objetos sin distincion y a su vez utilizarlos de manera directa como si fueran los mismos. Espero les haya sido de utilidad y les dejo un link a GitHub donde estan los codigos creados hoy:
Les dejo algunas de mis redes sociales para seguirme o recibir una notificacion cada vez que subo un nuevo post:


Donación
Es para mantenimento del sitio, gracias!
$1.50





