Sistemas de control

Como hemos visto en el post “sistemas“, existen dos tipos de sistema en nuestro proyecto. El primero, que describiremos en este post, son los sistemas de control.

Un sistema de control se caracteriza por manejar GameObjects con el fin de dar cuerpo al juego que se esté desarrollando. Esto es, un tipo de sistema que controlan y manejan el comportamiento del programa o juego.

El primero de ellos es el GameObject_Manager.

class CSystem_GameObject_Manager: public CSystem
{
  protected:
    friend class CSystem_Render;

    map<string, CGameObject*> gameObjects;
    int last_ID;

  public:
    bool Init();
    void Close();

    // ...

    CGameObject* AddGameObject(string name, bool init = true); // cambiar con un enum
    bool DeleteGameObject(string name, bool remove_children = true);
    bool RemoveGameObject(string name);

    // ...

    CGameObject* GetGameObject(string name);
    CGameObject* operator[](string name);
};

Éste almacenará un mapa std::map (Nota: es posible que sea mejor usar un std::multimap, por si el número de elementos crece demasiado) de todos los objetos de juego globales en la instancia actual de nuestro juego (véase éste post reciclado para entender las instancias de juego, aunque no sea el concepto exacto, esto es lo de menos, e intentaré explicarlo después de los sistemas), conteniendo una clave de tipo string (identificador único de cada objeto) y un puntero al objeto en sí. Además, cada objeto tendrá su propio identificador numérico (cosas internas al sistema), asignados por el manager a partir del valor last_ID (cada vez que se añade un objeto, se incrementa su valor, y cada vez que se llegue a un tope max_int, se reconstruye el índice de objetos, por si han quedado IDs al borrar objetos). El manager permite además añadir, obtener, modificar, borrar del sistema (remove) y destruir (delete) objetos de juego, permitiendo al usuario hacer uso de un entorno dinámico de juego.

El comportamiento del sistema es el siguiente: Primero, al inicio de cada instancia o nivel, el sistema inicia todos los objetos iniciando valores a nulo e iniciando los componentes, y llamando a la función start del objeto. Posteriormente, en cada iteración, si hay algún evento pendiente (movimiento de ratón, escalado de ventana, etc), se llamará a la función event de todos y cada uno de los objetos. Luego, se llamará a las funciones keyevent behaviour para definir el comportamiento del objeto, a partir del teclado y de su voluntad, respectivamente, y actualizando los valores necesarios. Finalmente, al acabar la instancia, el manager cierra y libera todos los objetos usados actualmente (guardados en el mapa gameObjects).

El segundo sistema de control es el sistema Render.

class CSystem_Render: public CSystem
{
  private:
    SDL_Window* window;                       // Ventana de SDL2
    SDL_GLContext GLcontext;                  // Contexto de OpenGL
    vector<CGameObject*> camera_list;         // Lista o cola de cámaras para renderizar

    inline void ResizeWindow(int w, int h);
    inline void ApplyCameraChanges();         // Aplicar cambios de renderizado de las cámaras

  public:
    CSystem_Render(): window(NULL){ };

    bool Init();
    void Close();

    void SetMainCamera(CGameObject* camera);  // Añadir cámara al principio de la cola

    void AddCamera(CGameObject* camera);      // Añadir cámara la última en la cola
    void AddCameraPrior(CGameObject* camera); // Añadir cámara la segunda en la cola

    void RemoveCamera(const string& camera);  // Eliminar cámara de la cola

    void OnLoop();
    void OnRender();
      void RenderGrid(int rows = 20, int cols = 20);
      inline void Clear();
      inline void RenderToScreen()
      {
        SDL_GL_SwapWindow(window);
      }

    inline void GetWindowSize(int* w, int* h)
    {
      SDL_GetWindowSize(window, w, h);
    }

};

El objetivo del render es coger el conjunto de objetos almacenados en el manager y plasmarlos de forma visual en nuestra pantalla o ventana. Para ello, debemos crear una ventana (SDL_window) con la API de SDL2, que contendrá los buffers y las cosas necesarias para mostrar por pantalla. Además, se creará un contexto de OpenGL para establecer un contacto con el hardware gráfico (y ese tipo de cosas incomprensibles). Por último, almacenaremos una lista de objetos que serán nuestras cámaras, que no serán más que objetos con componentes de “cámaras” (nuevamente, hablaré de estos componentes más adelante), que permitirán visualizar nuestro espacio 3D. Cada una de esas cámaras tendrá un modo de vista (perspectiva y ortográfica), una porción de pantalla que ocupa (0% – 100%), la posición x,y que ocupa de la pantalla (0% – 100%) y un color de fondo.

Por ejemplo, un escenario con 2 cámaras, una principal que abarque toda la pantalla (main camera) y una cámara secundaria (que abarca una porción mucho menor), con fondo azul, ambas con modo de vista “perspectiva”, se vería de esta forma:

grid

El funcionamiento del render es bastante sencillo, y sigue el siguiente algoritmo:

1. Para cada cámara C de lista_camaras
  A. Seleccionar porción de pantalla de la cámara C
  B. Apuntar la cámara a la posición indicaba (por rotación o por objetivo (target)).
  C. Limpiar la porción de pantalla con el color de fondo.
  D. Para cada objeto O almacenado en el manager
    i.   Reiniciar posición del mundo 3D
    ii.  Trasladarse a la posición del objeto O
    iii. Dibujar todos los componentes de O que sean dibujables
2. Cambiar buffers para mostrar por pantalla

Tal cómo está planteado, es un poco ineficiente (por llamadas innecesarias a funciones vacías, o por mostrar objetos que ni siquiera salen en pantalla). A medida que avancemos, mejoraremos (o al menos lo intentaremos) estos aspectos.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s