Finalista

Tercero en fase local y finalista en la fase nacional. Sencillamente, cumplí el objetivo deseado, llegar a la fase final, y darme a conocer fuera de mi facultad. Felicitar también al proyecto http://qdemos.wordpress.com/ por su segundo puesto y por llegar a la fase final, y a http://rsquaredproject.wordpress.com/ por el primer puesto en la fase local.

Image

Un saludo a los lectores, y si hay alguno, espero manteneros informado 🙂

Página en ZehnGames

Para aquellos que vengan de susodicha página, sean bienvenidos al blog, a la forja, al canal lista de reproducción de youtube, y cualquier otro lugar relacionado con el proyecto.

Para los que no, simplemente una manera de intentar dar el proyecto a conocer. A ver si surge un público, por mínimo que sea.

CComponent_Audio_Source

Una vez definido el gestor de sonido CSystem_Mixer, se pueden definir los componentes que van a representar fuentes de sonido dentro del juego. 

Image

 

Las principales características de un sonido son las siguientes:

  • Frecuencia
  • Volumen
  • Silenciado/No silenciado
  • Pista de música o no (no es sonido 3D, sino mono).
  • Pista tipo bucle o no (repetición continua).
  • Empezar o no a sonar nada más cargar la estancia.
  • Afección o no por el tiempo (modifica la frecuencia de manera interna dependiendo del tiempo)
  • Reproducir o no en todas partes.
  • Distancia máxima de reproducción (mínimo volumen por degradación).
  • Distancia mínima de reproducción (máximo volumen por degradación).

Las operaciones básicas para realizar con este componente son:

  • Cambiar el sonido (fuente, recurso).
  • Reproducir el sonido de manera estática (Play(), requiere bindear con Bind() el sonido antes de usarlo). Es más eficiente para casos en los que se usará el sonido varias veces, de manera continua. Nota: Un sonido que ha sido bindeado debe ser desbindeado (UnBind() de manera manual, ya que el recurso permanecerá ocupado hasta su liberación).
  • Reproducir el sonido una única vez (PlayOneShot(), no requiere bindear). Es más eficiente para casos en los que se usará el sonido pocas veces, de manera esporádica.
  • Reproducir en un determinado punto.
  • Pausar, parar, rebobinar, etc.
  • Bindear a un buffer del sistema CSystem_Mixer, y desbindear el buffer ocupado.

Para entender las solicitudes de buffer con Bind() y UnBind(), simplemente basta con pensar que un sonido no es más que una estructura de datos sencilla, sin gestión de sonido. Para que funcione, una entidad externa (CSystem_Mixer), debe ser capaz de proporcionar los medios necesarios para reproducir el sonido deseado. Para ello, proporciona una serie de buffers o “sources” para almacenar sonidos. Si se pide registrar un buffer con Bind(), el sistema guardará el sonido en el buffer para un uso cómodo y rápido, evitando esperas por el movimiento de sonido entre buffers. Así, es el usuario el que decide como gestionar el sonido, de manera que, manualmente, deba liberar los recursos que quiera (con UnBind()). No obstante, un sonido bindeado sólo se prodrá reproducir una vez cada vez, haciendo imposible reproducir un sonido varias veces (como disparos consecutivos).

Por otra parte, las acciones del tipo PlayOneShot() no requieren del uso de Bind(). Esto reside en que, de manera automática, se solicita un buffer temporal en el sistema CSystem_Mixer, y una vez acabado, se libera el recurso de manera automática. Por desgracia, este tipo de sonidos no se pueden modificar de manera dinámica, por lo que no se verán afectados por cambio de sonido, u otros elementos. Esto sí que permite repetir sonidos de manera continua (disparos, etc). Se recomienda usarlo para sonidos cortos.

Manual de usuario y CMake

Brevemente, diré que hemos empezado a realizar un pequeño manual de usuario para guardar todo el contenido relativa a la documentación general del proyecto. Además, más adelante, intentaremos generar documentación para el código con doxygen.

Finalmente, hace un rato he estado indagando (de manera frustrante, la verdad) con CMake, y creo que el proyecto ha sido puesto a punto para funcionar correctamente con cmake, incluyendo buscadores de dependencias (OpenGL, SDL2, Assimp, etc.).

Esperamos tener más tiempo para seguir trabajando en el proyecto, y poder aportar nuevas noticias al blog con calma.

Sin tiempo

Image

 

Simplemente, quería poner un mensaje de notificación para decir que tenemos muy poco tiempo para el proyecto gracias a la cantidad absurda de prácticas de este cuatrimestre.

Esperamos tener algo más de tiempo, por lo menos para documentar lo que tenemos hecho, y seguir implementando contenido.

Nuevo sistema auxiliar: Mixer

Con la necesidad de añadir sonido a nuestro motor gráfico, hemos creado un nuevo sistema auxiliar llamado CSystem_Mixer para encapsular la librería de OpenAL. El funcionamiento del sistema de sonido es bastante sencillo de cara al usuario: si un objeto necesita reproducir un sonido o una pieza musical, entonces deberá usar el componente CComponent_Audio_Source (que explicaré en próximos posts), y este hará uso de manera cómoda del sistema mencionado anteriormente, como en el siguiente esquema:

SAMSUNG

Para ello, se definirá el sistema con las siguientes características en el sistema:


class CSystem_Mixer: public CSystem
{
  friend class CComponent_Audio_Source;

  private:
    // Buffers reservados "one shots"...
    vector< ALuint > oneshot_used;
    vector< ALuint > oneshot_unused;

    // Buffers normales
    vector< ALuint > sources_used;
    vector< ALuint > sources_unused;

    uint NUMBER_SOURCES;
    uint NUMBER_SOURCES_ONESHOT;

    ALuint GetFreeSource();
    void AddFreeSource(ALuint source);

    ALuint GetFreeOneShot();

  public:
    CGameObject* listener;

  public:
    CSystem_Mixer(): CSystem() {};

    bool Init();
    void Close();

    void OnLoop();
};

Primero, se definen 4 vectores:

  • Vectores para sources o emisores de OpenAL que serán usados de manera continua, y se generarán un total de NUMBER_SOURCES (225 por defecto), cargadas de la variable __SOUND_NUMBER_SOURCES del sistema CSystem_Data_Storage. Se dfinirán dos vectores: sources ocupados o usados y sources sin usar. Si el mixer se queda sin sources, devuelve un error por consola.
  • Vectores para sources a los que hemos llamado OneShots, que consisten en sonidos que se se reproducirán una vez y se liberará una vez haya acabado, teniendo un total de  NUMBER_SOURCES_ONESHOT (30 por defecto), cargadas de la variable __SOUND_NUMBER_SOURCES_ONESHOT. Esto es ideal para sonidos cortos que se reproducen continuamente (explosiones, disparos…). Al igual que el anterior, se definen dos vectores: oneshots que están siendo usados y sin usar. Si se intenta emitir un sonido de este tipo y no quedan oneshots disponibles, se devuelve un error por consola. Si se prevee que no hay suficientes oneshots para una determinada instancia, se puede aumentar el número de oneshots cambiando la variable mencionada anteriormente, y los cambios se verán reflejados en la próxima vez que se llame a Init() del Mixer.
También, se definirá un único oyente por instancia para que funcione de manera correcta, que se encargará de recibir los sonidos cercanos y reproducirlos en función de su posición, orientación (no implementado) y velocidad (no implementado). Si no se especifica ninguno, se tomará como oyente a la cámara principal del sistema. Si no se ha definido ninguna cámara, entonces el sistema Mixer no funcionará. 
El objetivo del sistema es asignar sources normales a los componentes AudioSource que soliciten por medio de su método Bind() ocupar un source. Si se llama a Unbind() en dicho componente, se liberará el source que ocupa. De igual manera, hará algo similar con los oneshots, sólo que los componentes solicitarán reproducir un sonido de este tipo con PlayOneShot() (o con PlayAt(pos) (no implementado)), que el sistema Mixer comprobará en cada iteración si debe liberar el source o no, moviéndolo de un vector a otro.
Finalmente, el Mixer debe actualizar en cada iteración la posición del oyente de OpenAL con respecto a la de nuestro oyente o listener, además de actualizar la posición de los sources (no los oneshots) con las propiedades de transformación del objeto que contiene el componente AudioSource.

Vacaciones + Exámenes

Hemos tenido un largo periodo para descansar (dulces fiestas de navidad) y otro periodo aún más largo para estudiar para los exámenes, y por consiguiente, presentarnos a ellos.

Por supuesto, hemos tenido algo de tiempo libre para programar cosillas relacionadas con este proyecto. Pero, con pocas ganas de trabajar mucho, y pudiendo gastar el tiempo en cosas que nos “apetecen más”, habíamos decidido darle una pausa a este proyecto. Por supuesto, ahora que empieza el nuevo cuatrimestre, usaremos el tiempo que tengamos para trabajar en él, viendo el progreso que esperamos que tenga.

lazyprogrammer_gyxvv

Salud y buenas tardes.

CComponent_GUI_Texture

Otro componente interesante relacionado con el render es mostrar una interfaz gráfica de usuario por medio de una “capa” mostrada en nuestra pantalla. Se podrán mostrar texturas (implementado en este componente) y texto (no implementado aún) de tal forma que se ajusten de manera cómoda a la pantalla.

gui

El funcionamiento de este componente tiene 2 partes: una nueva funcionalidad en el Render y otra parte en el componente en sí:

  • En el Render, se ha definido una nueva cámara, llamada __GUI_Camera, encargada de renderizar el contenido de los componentes GUI. Dicha cámara se caracteriza por tener una proyección del tipo ortográfica en el origen de nuestro mundo. Por tanto, se renderizarán de la siguiente forma:
1. Desactivar el buffer de profundidad (GL_DEPTH_BUFFER).
2. Ajustar el viewport de la pantalla.
3. Cargar matriz ortográfica en la matriz GL_PROJECTION.
4. Para cada componente GUI hallado en el primer recorrido de objetos (main camera):
   5. Renderizar el componente GUI.

  • En el componente GUI se guarda un color, una textura o material, un ancho y un alto (valores entre 0 y 1) y un offset dado por píxeles. Y ahora decimos… ¿Cómo se guarda la posición de la textura en la pantalla? Para ello, usamos el componente Transform, que nos serviará para guarda la posición en pantalla (X e Y con valores entre 0 y 1, siendo el 0 la izquierda, el 1 la derecha para la X, y el 0 abajo y el 1 arriba para la Y, y un valor de Z que nos dirá qué elementos GUI van delante y cuales van detrás (uno con un valor Z menor que otro se dibujará después que otro), la escala (como se expande la textura o texto) y la rotación (como se rota el elemento con respecto a su centro). Para el renderizado, se hace lo siguiente:
1. Trasladarse a la posición dada por el componente Transform del objeto (position).
2. Rotar por un ángulo dado por el componente Transform del objeto (angle).
3. Escalar por un factor dado por el componente Transform del objeto (scale).
4. Seleccionar textura y color.
5. Dibujar aplicando offsets.