Anuncios

Bienvenidos sean a este post, hoy verremos el diseño de los integrantes del juego.

Anuncios

Tal como vinimos viendo hasta ahora cada unidad tendra su propia clase pero cada una de ellas compartiran propiedades y metodos de una clase base porque todas las usaran. Veamos un ejemplo que podemos tener de clase base:

class Unidad
{
public:
	void ataque(const Unidad &);
	void destruir();
	int get_puntos_vida();
	int get_poder();
};
Anuncios

Estas son acciones basicas que tendran todas las unidades. El ataque como la destruccion de la misma, a su vez cada una debe obtener los puntos de vida que posee como la potencia de ataque. Veamos como puede ser una clase de una unidad:

class Lector : public Unidad
{
public:
	void restar_puntos_vida(int &);
	void ataque(const Unidad &);
	void destruir();
	int get_punto_vida();
	int get_poder();
private:
	int puntos_vida_ = 10;
	int poder_ = 1;
};
Anuncios

Como pueden ver vamos a tener que sobreescribir los metodos de la clase base, y agregamos una nueva para restar puntos de vida por cada ataque recibido. En la parte privada tenemos los puntos de vida y su poder de ataque.. Siendo que cada unidad tendra los propios y unicos. Esto es algo muy basico de como manejarlo, pero podemos mejorar a la clase base de la siguiente manera:

class Unidad
{
public:
	virtual void ataque(const Unidad &) = 0;
	virtual void destruir() = 0;
	virtual int get_puntos_vida() const = 0;
	virtual int get_poder() const = 0;
};
Anuncios

De esta manera, no solo la convertimos en una virtual pura sino que tambien impedira que se puedan crear instancias u objetos de la clase base pero no evitara que podamos usarla para crear de las clases herederas. Pero ahora si nos vemos en la obligatoriedad de definir a estos metodos, para ello podemos hacerlo de la siguiente manera:

class Lector : public Unidad
{
public:
  Lector();
  Lector(const Lector&) = delete;
  Lector& operator=(const Lector&) = delete;

public:
  void ataque(const Unidad& atacante) override {
    restar_puntos_vida(atacante.get_power());
  }

  void destruir() override {
    // Lo dejamos vacio por ahora.
  }

  int get_puntos_vida() const override {
    return puntos_vida_;
  }
 
  int get_poder() const override {
    return poder_;
  }

private:
  void restar_puntos_vida(int num) {
    puntos_vida_ -= num;
    if (puntos_vida_ <= 0) {
      destruir();
    }
  }

private:
	int puntos_vida_;
	int poder_;
};
Anuncios
Anuncios

Tenemos nuestro constructor predeterminado y luego dos definiciones que se usan para evitar que se hagan copias del segundo constructor y la redefinicion del operador, lo siguiente son definiciones de los metodos de la interfaz y utilizados por nuestra unidad. El primer metodo es ataque y sera para cada vez que recibimos un daño. Este llamara al metodo encargado de restar puntos de vida y como argumento le pasamos el poder de la unidad que nos ataca, sobre este metodo hablaremos en un momento. El siguiente metodo es destruir y sera el encargado de eliminar a la unidad del juego pero por el momento la dejaremos en blanco. Para luego definir los metodos getter tanto de puntos de vida como de poder respectivamente. Todo esto que comentamos anteriormente es en la parte publica, pasemos a la parte privada. En esta no solamente tendremos las propiedades de los puntos de vida y poder para atacar sino que tambien tendra al metodo encargado de restar puntos de vida. Este sera definido aca, para que solamente puede ser llamado dentro de la clase y evitar que se llame desde un objeto o instancia.

Anuncios

Este restara el valor recibido a los puntos de vida y una vez que esta llegue a cero o sea menor que este procedde a llamar al metodo encargado de eliminar a la unidad. Como pueden ver ya tenemos bastantes aspectos de nuestra unidad cubierta, permitiendo que podamos crearla de la siguiente manera:

Lector lector;
Lector* pr = new Lector();
Unidad* up = new Lector();
Anuncios

No solamente podemos hacerla mediante nuestra clase sino tambien por la clase base, tal como mencionamos al convertirla en virtual pura. Esto es una gran mano, sobre todo cuando tenemos distintas unidades que deben interactuar entre ellas. Tomemos el siguiente caso como ejemplo:

int calcular_dano(const std::vector<Unidad*>& unidades)
{
  return std::reduce(unidades.begin(), unidades.end(), 0, 
            [](Unidad& u1, Unidad& u2) {
                return u1.get_poder() + u2.get_poder();
            }
  );
}
Anuncios

Esta funcion nos permite calcular el daño que varias unidades puedan realizar a un edificio. Como estas pueden ser varias en lugar de referenciar a todas las posibles, pasamos a la clase base y esta nos servira como referencia para cualquiera de las disponibles. Esto funciona porque garantizamos que el metodo get_poder sin importar la unidad siempre estara definido y por lo tanto el de la clase base podra ser utilizado.

Anuncios

En resumen, hoy hemos visto como diseñar de forma breve a las unidades, porque usar una clase base y que sea virtual pura, a su vez algunos beneficios que puede traernos por tomar esta conducta con respecto a otras acciones del juego. Espero les haya sido de utilidad sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios

Donación

Es para mantenimento del sitio, gracias!

$1.50