Anuncios

Bienvenidos sean a este post, hoy veremos como aplicar otro de los pilares fundamentales en OOP.

Anuncios

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.

Anuncios

Pero para ello, necesitaremos el codigo del post anterior. Sino lo poseen les dejo un link para descargarlo:

Proyecto Juego

Anuncios

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

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.

Anuncios

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;
Anuncios

Y lo modificaremos de la siguiente manera:

	ObjetoJuego* m_obj;
	Jugador* m_jugador;
Anuncios

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;
Anuncios

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.

Anuncios
Nota: 
Para habilitar a vector debemos agregar entre los include a #include <vector>
Anuncios

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");
Anuncios

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);
Anuncios

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();
}
Anuncios

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();
    }
}
Anuncios

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

Anuncios

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__
Anuncios

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() {}
Anuncios

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"
Anuncios

Nuestro siguiente paso sera generar el objeto en el archivo de encabezado mas exactamente en la parte protegida:

Enemigo* m_enemigo;
Anuncios

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);
Anuncios

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

Anuncios

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.

Anuncios

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:

Polimorfismo / GitHub

Les dejo algunas de mis redes sociales para seguirme o recibir una notificacion cada vez que subo un nuevo post:

Anuncios
pp258

Donación

Es para mantenimento del sitio, gracias!

$1.50