sábado, 10 de septiembre de 2011

Primer vídeo

music: SPACE AGE PLAYBOYS -"The Band Gets High"-



Pues... eso. Hasta otra. :P

viernes, 9 de septiembre de 2011

El problema "curioso" (y su resolución)

music: PJ HARVEY -"This Is Love"-

Durante las últimas semanas me he dedicado a solucionar el problema "curioso" del que ya hablaba en la entrada del día 12/05/2011.

Se hacía imprescindible poder dar una solución a esto si pretendía grabar el inplay del juego; como comentaba en la entrada anterior, era imposible hacer un vídeo que se viera decentemente debido al enorme lag que se producía.

Afortunadamente ya dejé hace tiempo las pistas necesarias por donde podía ponerme a empezar a trabajar para solventar esto... y los resultados han sido muy satisfactorios. : )

Al contrario de lo que pensaba el Componente LogicaPelota no era el problema... pero sí la puerta de entrada para ir, poco a poco, "buceando" en el código hasta llegar al núcleo principal de los problemas: los métodos IBounding::GetCollision e IBounding::GetPoints.

La optimización, realizada principalmente en dichos métodos, ha llevado a aumentar el framerate del juego (estando en modo Debug) hasta los... ¡¡¡147-150 FPS!!!. Teniendo en cuenta que, en estas mismas condiciones, las medidas marcaban 46-48 FPS ( hace tiempo hice algunas pequeñas optimizaciones que lo subieron hasta ahí desde la situación de (12/05/2011) ) el empuje ha sido espectacular. : )

Resumo las modificaciones que se han realizado para llevar a cabo la hazaña:

a) Dejar de devolver por valor un std::vector. Una de las cosas que he aprendido gracias a Quimera Engine es que, cuando devuelves por valor el resultado de un método, está sucediendo lo mismo que con los parámetros de entrada por valor: se está creando UNA COPIA del contenedor que alberga el resultado. Si dicho resultado es un std::vector, se tiene que crear UNA COPIA del vector... con lo que se estaba gastando inútilmente un montón de tiempo en cada iteración de GetPoints. Solución: poner un std::vector como un parámetro de salida en GetPoints, y por referencia.

b) Por lo que he podido ver, llamar al método std::vector.clear() en cada iteración de un método puede ser algo ASESINO. Hay que evitar a toda costa llamar a std::vector.clear() en un lugar que tiene que ejecutarse en cada iteración del juego, y con la mayor rapidez posible.

c) Asimismo, realizar múltiples llamadas a std::vector.push_back(elemento) en una misma iteración de un método (en concreto, unas 94 veces), también puede llegar a ser ASESINO. Hay que evitar realizar tantas llamadas a push_back en un lugar que tiene que ejecutarse en cada iteración del juego, y con la mayor rapidez posible.

d) La mezcla de b) y c) había dado un cóctel particularmente letal para el rendimiento. La solución ha sido sencilla:

d.1) Se fija un límite máximo de tamaño para los std::vector (en concreto, para los std::vector de puntos 3D) y se declaran ya con dicho tamaño. Así, ya no es necesario emplear ni clear para vaciarlos en cada iteración, ni push_back para añadir un elemento. Pueden ser los elementos introducidos directamente como si fueran arrays.

d.2) Al tener tamaño fijo ya no es posible emplear el método std::vector.size() para conocer cuántos elementos posee el vector. Por lo que se devolverá también, como parámetro de salida, una variable unsigned int que contendrá la cantidad de elementos que poseerá el vector. Dicho valor podrá ser empleado como centinela para recorrer el vector en un bucle for.

e) Por si fuera poco, había un fallo tonto en IBounding::Draw que estaba haciendo consumir inútilmente un montón de tiempo, y que ya ha sido subsanado.

Aparte... ciertos trucos de más bajo nivel, principalmente declaración de algunos grupos de variables locales a un método como static, que han hecho ganar algunos frames más... pero el gran avance en el rendimiento del juego ha sido gracias a lo explicado anteriormente.

La solución final es terminar de plantear e implementar el sistema de detección y respuesta de colisiones de una forma distinta a la actual, pero por el momento la optimización realizada ha sido suficiente. Al fín se ha podido grabar un vídeo. Ya veremos si continuo optimizando más o me voy a hacer otras cosas más urgentes (como introducir audio, por ejemplo).

Hasta otra. :P