jueves, 28 de febrero de 2013

PakEngine. Capitulo 7. Arreglando incidencias

Artículo perteneciente a la sección del PakEngine

Hola a todos,

En todo proceso de creación de software llega un punto en que tienes que intercalar el desarrollo de nuevas características con el arreglo de bugs que se han descubierto a posteriori.

Gracias a TDD, la incidencia de los bugs es mínima, siempre y cuando TDD se aplique bien. Lo digo por que en el proyecto me ha pasado justamente eso. Había una parte del pintado que no le apliqué TDD por que me parecía obvio que funcionaría bien. ¿Adivináis que me ha hecho romper la cabeza durante horas?

Aparte de resolver la incidencia de pintado (ahora ya pinta en el 0,0 como toca) he aplicado el código para hacer capturas de pantalla y gestionar el teclado.  Están escritas intentando ser lo máximo de cutres posible, en próximos capítulos las iré mejorando.

En el proceso de arreglo de incidencias he estado un tiempo leyendo y dándole vueltas al tema de la mantenibilidad, así que no os extrañéis si el código lo veis a partir de ahora del estilo de :
- Sin comentarios: Los comentarios acaban engañando por que no se mantienen, y no son más que una excusa para un "mal" código (si el código fuese bueno se debería poder entender sin comentarios)
- Reduciendo al máximo las duplicidades: Todo lo que sea copiar-pegar acaba en desgracia y es la fuente de gran parte de los programas.
- Funciones pequeñas : 3, 4 o 5 lineas, 20 las que más si están justificadas. Con esto se consigue que cada función haga solamente una cosa y sea sencilla.

Os recuerdo que si queréis revisar la lista de cambios la podéis consultar en la lista de subidas al svn  intento siempre que puedo poner comentarios que describan lo que subo. De la misma manera podeis consultar la lista de cosas que faltan por hacer  y proponer vuestras mejoras.

Con la última subida que he hecho  creo que ya tengo un motor de gráficos 2D que funciona, así que es muy posible que en breve haga un pong (por ejemplo) y una release de la dll para todos aquellos que les interese programar sus propios juegos.

Estoy ansioso por que proveis el motor y me digáis que le falta o que funciona mal.

Nos vemos,

LordPakusBlog

<< capitulo anterior                                                                                         siguiente capitulo >>

sábado, 23 de febrero de 2013

PakEngine. Capitulo 6. Refactorizando

Artículo perteneciente a la sección del PakEngine

Hola a todos,

En el capítulo anterior nos centramos en implementar TDD, así pues, lo lógico es que el capítulo de hoy se aproveche de TDD para refactorizar todo el código.

Si recordáis todo el código del motor estaba en un fichero (PakEngine.c); la gracia ahora está que con la única premisa de eliminar duplicaciones, todo ese código se puede ir modularizando y exportando a otros ficheros.

Concretamente el diseño que me ha surgido es este :
PakEngine
   |-> Render: Módulo que tiene las funcionalidades de pintado.
   |-> RenderList :  Módulo que tiene la funcionalidad de almacenar tareas de pintado.
   |-> SpriteList : Módulo que se encarga de almacenar recursos gráficos.

 Si os queréis bajar el código lo podéis hacer desde aquí

Para los incredulos, aquí teneis el código del PakEngine.cpp:

#include <stdlib.h>
#include <GL/glfw.h>

#include "PakEngine.h"
#include "RenderList.h"
#include "Render.h"
#include "SpriteList.h"

#include <iostream> //Usada para imprimir por consola

using namespace std;

#pragma comment(lib, "corona.lib")

//Funciones de pintado
DLLEXPORT void PAKENGINE_DrawGraf(int x, int y, int z, int id )
{
RENDERLIST_Insert(x,y,z,id);
}

//Inicialización, renderizado y deInit
DLLEXPORT void PAKENGINE_Init(char *cad,int w,int h)
{
  if (glfwInit() != GL_TRUE)
    exit(0);

  // 800 x 600, 16 bit color, no depth, alpha or stencil buffers, windowed
  if (glfwOpenWindow(w, h, 8, 8, 8, 0, 0, 0, GLFW_WINDOW) != GL_TRUE)
exit(0);

  glfwSetWindowTitle(cad);

  // set the projection matrix to a normal frustum with a max depth of 50
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(.5 * w, -.5 * w, -.5 * h, .5 * h, 1, 50);

  glMatrixMode(GL_MODELVIEW);       // Select The Modelview Matrix
  glLoadIdentity();         // Reset The Modelview Matrix
    glEnable(GL_TEXTURE_2D);       // Enable Texture Mapping ( NEW )
  glClearColor(0.0f, 0.0f, 0.0f, 0.5f);    // Black Background

}


//Nos devuelve si el loop de juego ha de seguir o no
DLLEXPORT int PAKENGINE_Render(void)
{
// escape to quit, arrow keys to rotate view
    if (glfwGetKey(GLFW_KEY_ESC) == GLFW_PRESS)
      return 0;

// Limpiamos la pantalla para preparala para el siguiente pintado
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0,0, -30);

//Renderizamos la escena.
RENDER_Run();

// swap back and front buffers
    glfwSwapBuffers();

return 1;
}

DLLEXPORT void PAKENGINE_DeInit(void)
{
  glfwTerminate();
  exit(0);
}

DLLEXPORT int PAKENGINE_LoadGraph(char cad[])
{
return SPRITELIST_Insert(cad);
}

 Que hemos conseguido con TDD??? Un código modular, simple y mantenible y sobretodo, seguro. Si en el futuro queremos mejorar el rendimiento del motor nos será muy fácil ya que tendremos la protección de TDD por si nos equivocamos.

Resumiendo, un proyecto en el que se disfruta trabajar.

Espero que os haya gustado.

Nos vemos,

LordPakusBlog

<< capitulo anterior                                                                                     siguiente capitulo >>

miércoles, 20 de febrero de 2013

PakEngine. Capitulo 5. Primeras pruebas con TDD

Artículo perteneciente a la sección del PakEngine

Hola a todos,

Ya tenéis subido en el repositorio el nuevo proyecto PakTest que se encarga de llevar el tema del TDD en el proyecto PakEngine.

Para los escépticos os diré que gracias a TDD  he encontrado un bug en el pintado, por el cual si introducías ordenes de pintado en sentido inverso de z (de menor a mayor), no ordenaba bien el vector de pintado, seguramente, de este bug habría tardado mucho a darme cuenta y lo que es peor, para cuando lo detectase es muy posible que estuviese ya enterrado entre cientos de lineas de código.

Como funciona PakTest??

Es una "libreria" que lo único que hace es darnos dos funciones muy sencillas para gestionar TDD: TDD_Assert y  PrintSummary.


void TDD_Assert(char *cad, bool isTrue)
{
num_run_test++; //Estamos ejecutando un nuevo test

if(isTrue)
{
num_ok_test++; //El test es ok.
}
else
{
std::cout << cad << std::endl;
num_fail_test++;
}
}

void PrintSummary(void)
{
if (!GetFailTest())
{
std::cout << "ALL TDD TEST ARE OK!!!" << std::endl;
  }
else
{
std::cout<< "TDD FAIL. STOP ALL AND FIX IT.RIGHT NOW!!!!" << std::endl;
}

std::cout << "Run: " << GetRunTest() << "  Ok: " << GetOkTest() << "  Fail: " << GetFailTest() << std::endl;
}

Con estas dos funciones podemos hacer tests muy sencillos y acumulativos que nos permitan asegurar que cierto código funciona como nosotros queremos. Por ejemplo:


PAKENGINE_DrawGraf(0,0,0, 0);
PAKENGINE_DrawGraf(0,0,0, 0);
PAKENGINE_DrawGraf(0,0,0, 0);
TDD_Assert("No introduce bien 3 tareas de pintado",max_draw_list == 3);

PAKENGINE_Render();
TDD_Assert("No limpia bien 3 tareas de pintado",max_draw_list == 0);



PAKENGINE_DrawGraf(0,0,50, 0);
PAKENGINE_DrawGraf(0,0,25, 0);
PAKENGINE_DrawGraf(0,0,0, 0);
TDD_Assert("No ordena bien 3 z's ordenadas", ((DrawList[0].z == 50) && (DrawList[1].z == 25) && (DrawList[2].z == 0)) );

PAKENGINE_Render();
TDD_Assert("No limpia bien 3 tareas de pintado ordenadas",max_draw_list == 0);

       PrintSummary();

Ahora el siguiente paso es refactorizar tanto los tests como el código del proyecto para eliminar redundancias y repeticiones de código, pero esto es ya tema del siguiente capítulo.

Fijaos que aunque parezca que se avance más lento en un principio (el hecho de hacer los tests de TDD mucha gente le tira para atrás), se gana en confianza en el código y en mantenibilidad, haciendo que el número de bugs que aparezcan en etapas posteriores sean mínimos y fáciles de encontrar y solucionar.

Espero que os guste el tema,

Nos vemos

LordPakusBlog

<< capitulo anterior                                                                                         siguiente capitulo >>


sábado, 16 de febrero de 2013

PakEngine. Capitulo 4. Pintado con z's y otros temas.


Artículo perteneciente a la sección del PakEngine

Antes que nada , el código de este capítulo lo podéis bajar de aqui

En esta entrega he implementado la gestión de z's, a fin de que se puedan pintar diferentes capas de gráficos.

Lo he implementado "mal" (poco eficiente y poco mantenible) a ver si alguien se apunta a proponer una solución mejor.

Este es el código en cuestión, os lo dejo en vuestras manos:


DLLEXPORT void PAKENGINE_DrawGraf(int x, int y, int z, int id )
{
int i,j;

//Si no se ha insertado ningun gráfico hasta el momento, ponemos el primero
if(!max_draw_list)
{
DrawList[0].type = TYPE_GRAF;
DrawList[0].x = x;
DrawList[0].y = y;
DrawList[0].z = z;
DrawList[0].id = id;
max_draw_list = 1;
return;
}

for ( i = 0 ; i < max_draw_list ; ++i)
{
if(DrawList[i].z <= z)
{
//Desplazamos todos los elementos que van a ir despues
for ( j = i ; j < max_draw_list; ++j )
{
DrawList[j+1].type = DrawList[j].type;
DrawList[j+1].x = DrawList[j].x;
DrawList[j+1].y = DrawList[j].y;
DrawList[j+1].z = DrawList[j].z;              
DrawList[j+1].id = DrawList[j].id;
}

DrawList[i].type = TYPE_GRAF;
DrawList[i].x = x;
DrawList[i].y = y;
DrawList[i].z = z;              
DrawList[i].id = id;

max_draw_list++;

return;
}
}

DrawList[max_draw_list].type = TYPE_GRAF;
DrawList[max_draw_list].x = x;
DrawList[max_draw_list].y = y;
DrawList[max_draw_list].z = z;
DrawList[max_draw_list].id = id;
max_draw_list++;

}


En cuanto a las cosas que quedan por hacer, vamos a repasar la lista (he ido incluyendo nuevos items):

En cuanto a funcionamiento:
- Se debería implementar el sistema de Z's -> YA ESTA HECHO (solo falta mejorarlo)
- Se debería hacer que el 0,0 fuese una esquina de la pantalla, ahora está por el medio.
- Se debería buscar la manera de implementar el audio de manera más amigable que en los otros motores.
- Se debería implementar XML

En cuanto a calidad de código:
- Se debería diseñar un sistema TDD que nos pruebe automáticamente el código. IMPRESCINDIBLE.
- La interficie de trabajo debería ser una clase(singleton): Más que nada por el autocompletar funciones. Podríamos tener un puntero al motor y llamar a sus funciones de clase, de forma que todo quedase un poco más limpio de lo que tenemos ahora. Se aceptan sugerencias.
- Los vectores internos de pintado podrían ser vectors de stl y se podría acceder a los diferentes elementos mediante iterators. Quedaría más limpio el acceso a los datos.
- Se debería hacer un refactor general para purificar el código.

Otros:
- Se debería subir el código a un svn para controlar mejor las versiones

Espero vuestras propuestas para el tema de las z. En breve os iré informando de más avances.

Nos vemos,

LordPakusBlog

<< capitulo anterior                                                                                         siguiente capitulo >>

lunes, 11 de febrero de 2013

PakEngine. Capitulo 3. Mejorando la configuración del proyecto

Artículo perteneciente a la sección del PakEngine
Hola a todos,

Hoy me he dedicado a intentar compilar y hacer funcionar el motor en un ordenador que no es el mio de trabajo normal y me he llevado la sorpresa al ver que realmente la configuración del proyecto es horrible.

Mucha gente pensará que el proyecto como tal es lo de menos, mientras el código sea mantenible y eficiente, pero no es verdad, un proyecto mal configurado hace que trabajar con el sea poco menos que una tortura.

Así pues me he dedicado a ir arreglando todos los problemillas que he ido viendo de forma que cualquier se pueda bajar el proyecto  y compilar, sin mas. Os dejo la lista de cosas que tenéis que tener en cuenta:

1. Antes que nada, si queréis usar el PakEngine deberíais tener instalado algún Visual Studio C++ (para aprovechar la configuración de los proyectos y soluciones). Lo podéis bajar gratuitamente de aqui. En próximos capítulos intentaré montar un script de compilación para que sea sencillo construir el proyecto con otros compiladores.

2. En segundo lugar me he dado cuenta que las rutas de inclusión de includes(.h) y binarios(.lib) eran fijas y no relativas. Esto es un error grave ya que cada uno debe poder descargar el proyecto donde quiera y compilarlo como quiera.

3. El archivo gráfico de test (img_test.png) lo puse en medio de la carpeta donde estaba el ejecutable y la dll, esto (aunque afecte solamente al juego y no al motor) no es una buena práctica ya que se va ensuciando la zona donde tenemos el ejecutable.

4. En último lugar, pero no por ello el menos importante, todos los archivos intermedios se generaban en la misma carpeta donde se generaba el ejecutable y la dll. Es un error ya que es un engorro para buscar después lo que queremos que los demás usen. Se ha de crear una carpeta obj donde poner todos los archivos intermedios y decirle al compilador que ponga toda la información intermedia en esa carpeta.No he podido solucionar este problema para todos los archivos pero al menos en unos cuantos lo he ido solventando. En la medida que pueda lo iré arreglando.

Finalmente, si queréis bajaros todo esto solo tenéis que pulsar aqui

Espero que os sirva en vuestros proyectos,

Nos vemos

LordPakusBlog

<< capitulo anterior                                                                                         siguiente capitulo >>

domingo, 10 de febrero de 2013

PakEngine. Capitulo 2. Cargando y pintando gráficos

Artículo perteneciente a la sección del PakEngine

Hola a todos,

En estos momentos iniciales del proyecto lo único que hago es ir recopilando trozos de código antiguo de los otros motores para crear la parte inicial.

Si os queréis bajar el código y ejecutables de la demo del motor que carga y pinta gráficos, os lo podéis bajar de aqui. La demo no es del todo correcta, y tiene fallos que ya conozco y tengo apuntados, pero me sirve para ir avanzando.

Items que se que se han de arreglar/implementar en futuras versiones(hacedme llegar vuestras propuestas) :

En cuanto a funcionamiento:
- Se debería implementar el sistema de Z's (el vector de pintado existe, pero no ordena por z)
- Se debería hacer que el 0,0 fuese una esquina de la pantalla, ahora está por el medio.
- Se debería buscar la manera de implementar el audio de manera más amigable que en los otros motores.
- Se debería implementar XML

En cuanto a calidad de código:
- Se debería diseñar un sistema TDD que nos pruebe automáticamente el código.
- La interficie de trabajo debería ser una clase(singleton): Más que nada por el autocompletar funciones. Podríamos tener un puntero al motor y llamar a sus funciones de clase, de forma que todo quedase un poco más limpio de lo que tenemos ahora. Se aceptan sugerencias.
- Los vectores internos de pintado podrían ser vectors de stl y se podría acceder a los diferentes elementos mediante iterators. Quedaría más limpio el acceso a los datos.
- Se debería hacer un refactor general para purificar el código.



Esta lista la iré arrastrando durante todo el proyecto incluyendo y sacando elementos a medida que se vaya desarrollando. Todo aquello que vosotros me digáis irá a la lista.

Espero que os guste,

Nos vemos

LordPakusBlog

<< capitulo anterior                                                                                         siguiente capitulo >>

sábado, 9 de febrero de 2013

PakEngine. Capitulo 1. Iniciando el proyecto

Artículo perteneciente a la sección del PakEngine

Hola a todos,

Este primer capítulo va a servir para empezar a montar la base para todo lo que vayamos a construir encima.

Este artículo tiene básicamente dos objetivos:
- Crear un proyecto DLL
- Usar GLFW

En otras ocasiones he ido copiando el código de todo lo que he hecho y creo que es contraproducente. Es mejor que os pase el link de donde descargarlo y ya vosotros podáis ver el código.

El proyecto consta de dos partes: el PakEngine (motor gráfico que se compila generando una dll) y el PakGame (juego de prueba que usa la dll anterior) . Lo podéis bajar todo del siguiente link. Si tenéis problemas durante la compilación o ejecución decidmelo y le buscaremos solución.

Una vez lo tengáis bajado, descomprimidlo y abrid la solución.
Os debería salir algo de este estilo:

Lo único que tenéis que hacer ahora es darle con el botón derecho encima de la solución y escoger la primera opción ( generar solución ). Esto lo que hará será generar la dll y después generar el exe que use esa dll.

Una vez os compile os tenéis que ir a la carpeta de la solución (PakEngine), abrir la carpeta debug y ejecutar el PakGame.exe. Si todo ha ido bien debería apareceros algo de este estilo.



Poco a poco iremos haciendo que el motor tenga más funcionalidades y a ver si en poco tiempo podemos hacer un primer juegecillo

Espero que os guste, recordar que estoy abierto a sugerencias para el desarrollo del motor.

Nos vemos

LordPakusBlog

<< capitulo anterior                                                                                         siguiente capitulo >>

miércoles, 6 de febrero de 2013

Inicio de nuevo motor gráfico.

Artículo perteneciente a la sección del PakEngine

Hola a todos,

Como todos ya sabeis ya se han hecho unos cuantos motores gráficos y de juego en este blog (mejores o peores, en eso no me meteré :D ) y he ido acumulando experiencia sobre lo que si y lo que no se debe hacer, así que me veo con fuerzas para empezar desde cero otro motor.

La primera cosa importante ME FALTA NOMBRE!!! Así que se aceptan sugerencias, si queréis ponedlas en los comentarios a este post.

Características:
- Especial hincapié a la calidad del código : La mayoria de los proyectos que he hecho hasta ahora se han ido muriendo por la falta de mantenibilidad, así que este será un hecho a tener en cuenta desde el principio. Es posible que durante el proceso de creación del motor vaya incluyendo capitulo de integración continua , TDD o cosas por el estilo.

- Unido con el tema anterior, la refactorización será continua. Esto significa que de vez en cuando habrá posts sobre como se ha modificado el código para que sea más mantenible, sin dar nuevas funcionalidades. Una cosa que me ha pasado bastante es que los lectores me han ido proponiendo mejoras que he dejado para el final y ha sido una lástima por que para entonces ya era demasiado tarde, así que proponed mejoras sin manias.

- El proyecto será una DLL desde el primer dia: Uno de los problemas que he ido teniendo es que los motores se entremezclaban con los juegos y se llegaba a un punto en que era complicado separarlos. Es por eso que aunque sea un poco engorro probar las cosas prefiero que sea una DLL desde el primer dia. Nos da una ventaja adicional y es que se podrá aplicar TDD de forma totalmente separada al motor o a los juegos que implementemos.

- El motor será 2D (al menos en un inicio),el motivo es sencillamente por la complejidad vs calidad de un motor 3D. Se pueden obtener resultados bastantes buenos con 2D con relativo poco esfuerzo mientras que para tener algo cutre en 3D se ha de batallar mucho.

- Se intentará que el máximo de cosas sean configurables por XML para darle versatilidad al motor

- Tecnológicamente usará: openGL, GLFW, VC++,  threads, SSE

Espero que os guste la idea y os animéis a participar ni que sea probando y dando ideas.

Nos vemos

LordPakusBlog

Entradas populares