Bajo un océano de bits, mes X

Por Javier Albizu, 31 Octubre, 2018
Seguimos avanzando sin movernos del mismo lugar, cambiándolo todo sin que sea apreciable desde el exterior.

Datos. Necesito datos1.

Durante este mes me he centrado en sacar todos los valores que puedan ser utilizados en mas de un lugar fuera del código. Aparte de eso, el “contenedor maestro” que había creado para abarcar a todos los objetos se ha visto separado en cinco. Todo eso y poco más en esta edición de “Bajo un océano de bits” en su entrada más ¿técnica?.

Aún estoy dando pasos de bebé en esto de la programación en general, y el C++ en particular, pero estoy comenzando a “entender” estos lenguajes. Me estoy dedicando a jugar con ellos. Porque, por mayor que sea el misticismo que le queramos dar, la programación no deja de ser eso, otro idioma que tenemos que aprender a hablar, leer y escribir. Otra manera de describir las cosas.

Cuanto más profundizo, más claro tengo que es una cuestión de tiempo, práctica, paciencia, inventiva y objetivos acotables. Cuanto más básico es el nivel del código que leo, más me doy cuenta de que… tiene sentido. Que “eso habría sabido hacerlo yo”.
Si con el dibujo los engranajes de mi cabeza aún no han hecho “click”, parece que estos sí que van cogiendo velocidad.

Y es entonces cuando pienso que me estoy perdiendo algo. Que no puede ser tan sencillo. La historia de mi vida.

Pero la cosa es que muevo y reescribo, retuerzo las líneas en otro sitio y siguen funcionando. Que siguen haciendo lo que tenían que hacer (o al menos lo mismo que hacían cuando las describí de otra manera). Y eso hace que me sienta bien.

No dudo de que, hasta cierto punto, este no-avanzar de los últimos meses se debe a que he encontrado algo similar a una zona de confort, pero creo que lo que estoy haciendo tiene sentido. Tardaré más en ver resultados en la pantalla, pero tengo claro que los pasos llevan la dirección correcta.

Y claro, luego me pongo a leer más cosas y me doy cuenta de que, si quiero hacer las cosas bien desde el principio, voy a tener que esperar mucho más hasta que lleguen esos resultados y sean “visibles” (o jugables). No quiero empezar con pasos apresurados y darme cuenta a medio camino de que tenía que haber hecho algo distinto desde el principio.
No sé cuántas veces me han dicho que estoy tomando el camino difícil, pero yo no he venido hasta aquí a hacer sólo las cosas fáciles.

Quizás por deformación de mi trabajo en el día a día, sigo pensando en la arquitectura del programa a alto nivel. En tratar de desglosar los componentes de la forma más general, abstracta y óptima posible. De decidir a qué capa correspondería cada uno de ellos. En que todo lo que haga ahora sea reutilizable para cualquier cosa que pueda hacer después.

Dentro del nivel más básico de esta arquitectura que voy improvisando con cada nueva revisión, he situado los datos en crudo; lo que quiero que esté fuera del código. Un contenedor al que, en un alarde de originalidad, he dado en llamar “Datos”.

Para ello he creado una clase central a la que he llamado (redoble de tambores) “Acceso_datos”. Una clase que se basa en archivos de texto plano en el que iré insertando los valores que usará el programa y para cuya estructura he decidido utilizar JSON2

Por el momento Acceso_datos sólo tiene una función llamada “Leer”, que me devuelve los valores guardados en los archivos y los convierte en variables a utilizar por el código. Cosas de un amplio espectro que abarcan desde el idioma hasta la anchura de un rectángulo en el que voy a dibujar un sprite o la clasificación de los jugadores. Más adelante tendré que crear los métodos “Actualizar”, “Crear” y “Reiniciar”.

Nada más arrancar el programa, lo primero que hace es inicializar este contenedor, con lo que leerá cuatro archivos JSON con nombres tan genéricos como “datos_globales”, “datos_recursos”, “datos_controles” y “datos_clasificacion”.

Tras la creación de “Datos” le llega el turno al segundo elemento central que he creado. Algo que, en un nuevo alarde de originalidad, he bautizado como “Sistemas”. Este contenedor se encarga de albergar los objetos que hablan con los dispositivos de entrada y salida. Por el momento, dentro de “Sistemas” se instancian los objetos de otras dos clases; Pantalla y Controles.

Como ya digo, es el segundo objeto que se crea en el arranque del programa y, tras leer los valores que le proporciona “Datos”, inicializa los objetos “pantalla_principal” y “controles”.

Una vez hecho esto, procedemos a pasar al tercer gran contenedor; “Recursos”. En él, en estos momentos, sólo se inicializa el objeto “LOGO” de la clase “Imagen”, pero más adelante (cuando existan) será el encargado de albergar objetos de las clases “Fuentes”, “Sonidos”, “Música”.

Cada uno de estos objetos estará almacenado en vectores3 que se crearán dinámicamente a partir de la información del archivo “datos_recursos.json”. Con esto, una vez que tenga creadas todas las clases que aglutina, para meter un nuevo “recurso” no tendré que tocar para nada el código de este contenedor.

Para terminar tenemos el contenedor “Modos” (al que igual termino llamando “Presentacion” para que suene más parecido a la capa OSI que sería su homóloga). Los miembros de este contenedor utilizarán los objetos instanciados en los anteriores y, a su vez, instanciarán objetos de las clases “Presentacion”, ”Menu”, “Juego”, “Editor” y “Configuracion”.

De las clases que debe albergar “Modos” por ahora sólo existe “Menu” y aún se encuentra en un estado casi embrionario. Cuando cree la clase “Juego” también tendré que crear otra clase hijo a la que llamaré “Nivel”, pero aún no sé en que consistirá ninguna de las dos, así que tiempo al tiempo.

Aún me queda por definir el último contenedor que se debería crear. El que he dado en llamar “Motor” y que se ocupará de cosas como las físicas, detección de colisiones, animación (y otro montón de cosas con las que me pegaré cuanto toque).

Todo un berenjenal.

Últimamente tengo abiertos todos los archivos pertenecientes a las clases mencionadas y los archivos de datos que les corresponden. Esto significa que mis editores tienen abiertos de manera permanente cerca de treinta archivos entre los que navego. Cada vez que toco uno de ellos tengo que andar modificando alguno de alguno de los restantes, así que hay momentos en los que hago sufrir mucho al compilador con mis descuidos.

Hasta este mes no existía la parte de acceso a datos, y todos los demás contenedores se encontraban apretados dentro de uno que había denominado “Nucleo”. A priori esto resulta más sencillo, sólo tendría que tocar un archivo tocho, pero he preferido separarlos para que su estructura se parezca a algo que tenga un poco más de orden, sentido y estructura en mi cabeza. Hoy “Nucleo” era manejable, de aquí a un tiempo se habría convertido en un infierno (y en algo menos reutilizable).

El sacar los datos a los archivos JSON también me ha supuesto algún que otro problema adicional. En los archivos de cabecera podía definir los datos con el tipo que me de la gana, pero al importarlos desde fuera todos son cadenas de texto. Con ciertos valores, como las opciones de inicialización de la ventana la cosa se complica. Este valor, que en código puede ser una cadena de texto, por detrás hacía una conversión a hexadecimal, algo que no se puede (o no he conseguido) hacer directamente.
Tras analizar un poco el código de SDL he visto que donde yo ponía “SDL_HWSURFACE | SDL_RESIZABLE | SDL_DOUBLEBUF”, él hacía tres sustituciones:

#define SDL_HWSURFACE 0x00000001 /** Surface is in video memory */

#define SDL_RESIZABLE 0x00000010 /** This video mode may be resized */

#define SDL_DOUBLEBUF 0x40000000 /** Set up double-buffered video mode */

Así pues, al final la cosa se quedaba como la suma de esos tres valores, ergo: 0x40000011 (que es el valor que ha quedado en el archivo de configuración).
A saber con cuántas más de estas me voy a encontrar.

Otra parte que me ha consumido bastante tiempo ha sido la generación dinámica de los vectores de “Recursos”. Algo que, si bien no era un requerimiento ahora mismo, sí que me facilitarás las cosas de cara a futuro.

Por otro lado, la parte de una posible traducción de los textos que aparezcan en pantalla, por el contrario, ha sido una de las más sencillas de implementar. Ahora sólo falta que no me olvide de poner los valores correctos donde toca en cada nueva clase.

Una vez conseguido todo esto, se me abren varios caminos. Podría plantearme el meterme en serio con las fuentes de creación propia4 o que empiece a mirar maneras ágiles de probar las cosas que hago5.
Cualquiera de las dos cosas me va a llevar bastante tiempo. Aunque creo que la primera será más rápida de solventar, la segunda me va a a aportar más en el largo recorrido y este es un buen momento para ponerme a ello.

No sé. Mañana me podré con ello.

Enlaces:

1. Más datos

2. JSON
- JSON en la Wikipedia
- Jsoncpp en Github
- Jsoncpp en WikiBooks
- Json Parser 1
- Json Parser 2

3. Vector

4. Dibujando texto y fuentes
- Text Imput
- Getting String Input (SDL1)
- Introducción de texto con SDL (SDL2)
- Text Input And Clipboard Handling (SDL2)
- SDL_ttf
- Ejemplo de implementación de SDL_ttf
- Bitmap Font Generator
- Bitfont Maker 2
- Unicode

5. Probando que es gerundio
- Test-driven development and unit testing with examples in C++
- Ten C++ Testing Tools for Developers to Consider
- CppUnit
- Google Test
- Boost.Test
- Catch2
- Bandit
- Cpputest
- TUT (C++ Template Unit Test Framework)

El contenido de este campo se mantiene privado y no se mostrará públicamente.

Plain text

  • No se permiten etiquetas HTML.
  • Las direcciones de correos electrónicos y páginas web se convierten en enlaces automáticamente.
  • Saltos automáticos de líneas y de párrafos.