miércoles, 11 de diciembre de 2013

Segundo Proyecto: Creación de los componentes

En esta entrada vamos a ver como crear los elementos que compondrán las distintas partes del juego. En esta ocasión he juntado tres patrones de diseño en una sola clase. Estos son un singleton, una factoría y un builder.

MessageHandler & Singleton


Para nuestros propósitos necesitamos que exista una única copia de la clase que hace de factoría, además también necesitamos que esta factoría pueda recibir mensajes desde otras partes del juego para crear los elementos según sean necesarios.
Para ello he tomado una clase derivada de MessageHandler y le he dado la forma de singleton.

#ifndef _GEL_GAME_FACTORY_H_
#define _GEL_GAME_FACTORY_H_

#include "Core/MessageHandler.h"
#include <map>

namespace Gel
{
 namespace Game
 {
  class CreatorBase;
  class BuilderBase;

  class Factory: public Core::MessageHandler
  {
  public:
   DECLARE_RTTI;

   ///        @fn GetInstance
   ///        @brief Get The Intance of the factory
   ///
   ///        A singleton static function to create a unique factory
   static Factory& GetInstance();

   ///        @fn RegisterCreator
   ///        @brief Add a creator for a messagehandler
   ///
   ///        Register a creator to make a piece of a game element
   void RegisterCreator(unsigned int creatorId, const CreatorBase* creator);

   ///        @fn UnregisterCreator
   ///        @brief Eliminate a creator from database
   void UnregisterCreator(unsigned int creatorId);

   ///        @fn Create
   ///        @brief find and execute the creation of a messagehandler
   Core::MessageHandler* Create(unsigned int creatorId, const Base::DataPack& extraData);

   ///        @fn RegisterBuilder
   ///        @brief Add a complex game element builder to DB
   void RegisterBuilder(unsigned int creatorId, const BuilderBase* builder);

   ///        @fn UnregisterBuilder
   ///        @brief Eliminate a Builder from DB
   void UnregisterBuilder(unsigned int creatorId);

   ///        @fn Build
   ///        @brief Crete a complex game object
   void Build(unsigned int creatorId, const Base::DataPack& extraData);

   ///        @fn HandleMessage
   ///        @brief Get a message and process it
   void HandleMessage( unsigned int fromHandlerID, unsigned int messageID, const Base::DataPack& extraData );

   ///        @fn Notify
   ///        @brief Get a notification and process it
   void Notify( unsigned int notificationID, const Base::DataPack& extraData );

  private:
   ///        @fn (constructor)
   ///        @brief default constructor
   Factory();

   ///        @fn (copy constructor)
   ///        @brief copy constructor
   Factory(const Factory& other);

   ///        @fn operator=
   ///        @brief assignation opetator
   const Factory& operator=(const Factory& _other);

  protected:
   typedef std::map<unsigned int, const CreatorBase*> CreatorMap;
   typedef std::map<unsigned int, const CreatorBase*>::iterator CreatorIterator;

   CreatorMap m_creators;

   typedef std::map<unsigned int, const BuilderBase*> BuilderMap;
   typedef std::map<unsigned int, const BuilderBase*>::iterator BuilderIterator;

   BuilderMap m_builders;
  };

 } //End of Game
} //End of Gel
#endif

Como podéis ver tiene las funciones necesarias de un MessageHandler (HandlerMessage y Notify), y sus constructores son privados, por lo que nadie puede crear una factoría a través de un new, como todo singleton de los que yo utilizo tiene una función static que si es necesario crea la factoría y nos devuelve la instancia única.

Como MessageHandler tiene un ID, sin embargo, este identificador único no nos interesa ya que accedemos a esta clase a través de la función estática.

La Factoría


Un patrón factoría no es mas que un objeto donde se centraliza la creación de los objetos del programa. Para crear un determinado objeto se le indica a la factoría con un identificador que elemento se quiere crear y este te lo devuelve.

Existen muchas formas de hacer una factoría, he optado por un sistema de registros de clases creadoras.

Se tiene una clase creadora, todas derivadas de una clase creadora base, cuyo único objetivo es hacer un new de la clase que se desea crear. Todas esas clases se registran dentro de la factoría con un identificador y de esta forma se pueden crear objetos tan solo diciéndole a la factoría que identificador usar.

Podéis ver en código de arriba como hay dos funciones para registrar y borrar CreatorBase, y una que sirve para crear según un identificador.

El Builder


Un Builder es un patrón de diseño que se utiliza cuando se requiere crear un objeto a partir de varios procesos distintos.

En nuestro caso los elementos de nuestros juegos serán objetos formados por varios MessageHandler ( Datos, Vista Controlador ) de distinto tipo según el objeto que además tienen que crearse en un orden determinado.

Para eso tenemos un objeto cuya única función es crear los distintos elementos en orden y realizar las operaciones necesarias para construir el nuevo elemento.

Podía haber creado otro singleton similar a la factoría de arriba y en el haber registrado y borrado los objetos Builder, sin embargo he preferido meterlo todo en el mismo singleton.

Por ello hay tres funciones, parecidas a las de la factoría, que sirven para mantener un registro de los objetos Builder y poder acceder a ellos. Los objetos Builder a su vez crearan las piezas a través de los Creator.

Conclusión


La creación de objetos esta todavía muy verde y de una forma muy abstracta hasta que no empecemos a usarla en el juego. En realidad es muy sencillo de usar, solo hay que superar el pensamiento de programación lineal.

Gracias por vuestra atención.

1 comentario:

nlbi21 dijo...

David, ante todo gracias por tus tutos estoy muy agradecido estoy aprendiendo un montón en el área de creación de juegos ahora tengo un proyecto en mente, estoy haciendo la parte del diseño y pensando en las mecánicas antes de meterme de lleno a programar, estoy estudiando ingeniería en sistemas, ademas de que este proyecto me sirve de practica, también me divierte bastante programar, me gustaría que siguieras con tus tutoriales por que en la parte de realizar motores estoy crudo, y repito gracias por estos valiosos tutoriales.