Vale, os cuento.

Antes de ponerme a terminar las cosas que hay pendientes, me vi en la obligación de cambiar el analizador sintáctico XML que emplea el juego para leer los archivos de datos. Tuve que hacerlo porque aunque en la versión Linux no había problemas, me las veía moradas para compilar en Windows la biblioteca libxml++. Terminé tan harto que pensé en buscar otra alternativa...
Y la encontré: ahora uso el analizador XSD de CodeSynthesis. Una auténtica virguería que construye clases C++ a partir de un esquema XSD. Os pongo el esquema para definir los elementos del juego:
- Código: Seleccionar todo
<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="items" type="ItemsXML"/>
<xsd:complexType name="ItemsXML">
<xsd:sequence>
<xsd:element name="item" maxOccurs="unbounded">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="door" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="north"/>
<xsd:enumeration value="south"/>
<xsd:enumeration value="east"/>
<xsd:enumeration value="west"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="widthX" type="xsd:int" maxOccurs="3"/>
<xsd:element name="widthY" type="xsd:int" maxOccurs="3"/>
<xsd:element name="height" type="xsd:int" maxOccurs="3"/>
<xsd:element name="directionFrames" type="xsd:byte"/>
<xsd:element name="mortal" type="xsd:boolean"/>
<xsd:element name="weight" type="xsd:double"/>
<xsd:element name="framesDelay" type="xsd:double"/>
<xsd:element name="speed" type="xsd:double"/>
<xsd:element name="bitmap">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="frameWidth" type="xsd:int"/>
<xsd:element name="frameHeight" type="xsd:int"/>
</xsd:sequence>
<xsd:attribute name="file" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="shadow" minOccurs="0">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="shadowWidth" type="xsd:int"/>
<xsd:element name="shadowHeight" type="xsd:int"/>
</xsd:sequence>
<xsd:attribute name="file" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="extraFrames" type="xsd:int" minOccurs="0"/>
<xsd:element name="frame" type="xsd:int" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="label" type="xsd:short" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
Este esquema se usa para validar que la información de los archivos es correcta. El archivo XML de definición de elementos tiene este aspecto:
- Código: Seleccionar todo
<?xml version="1.0" encoding="UTF-8"?>
<items xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="items.xsd">
<!-- Brick #1 -->
<item label="1">
<widthX>16</widthX>
<widthY>16</widthY>
<height>24</height>
<directionFrames>1</directionFrames>
<mortal>false</mortal>
<weight>0.032</weight>
<framesDelay>0</framesDelay>
<speed>0</speed>
<bitmap file="gfx/item/brick1.bmp">
<frameWidth>64</frameWidth>
<frameHeight>56</frameHeight>
</bitmap>
<shadow file="gfx/item/brick1-shadows.bmp">
<shadowWidth>64</shadowWidth>
<shadowHeight>31</shadowHeight>
</shadow>
<frame>0</frame>
</item>
<!-- Vulcano -->
<item label="2">
<widthX>16</widthX>
<widthY>16</widthY>
<height>24</height>
<directionFrames>1</directionFrames>
<mortal>true</mortal>
<weight>0</weight>
<framesDelay>0</framesDelay>
<speed>0</speed>
<bitmap file="gfx/item/vulcano.bmp">
<frameWidth>64</frameWidth>
<frameHeight>56</frameHeight>
</bitmap>
<shadow file="gfx/item/vulcano-shadows.bmp">
<shadowWidth>64</shadowWidth>
<shadowHeight>31</shadowHeight>
</shadow>
<frame>0</frame>
</item>
...
</item>
El analizador, como he dicho, construye una clase que da acceso mediante operaciones de consulta a toda la información contenida de un modo sencillo y limpio. Fantástico. Tiene un problema, que depende del analizador Xerces de la Fundación Apache y aunque viene preparado para compilarlo con las herramientas de Microsoft, al no usarlas, me he visto en la obligación de ver cómo compilarlo para MinGW. No ha sido difícil y ya está hecho.
Por otra parte he querido pulir el código que tenía ya hecho. Diréis que así no se avanza rehaciendo cosas, pero merecerá la pena cuando andemos probando. Además, pensad que el motor debe ser fácilmente ampliable pues lo usaremos para otros proyectos: la versión 1.5, la segunda parte, algún otro
remake, quizá.
Hoy he terminado el pulido y estoy muy contento. He aplicado patrones de diseño, concretamente el patrón Constructor, el patrón Mediador y el patrón Compuesto. Un buen diseño orientado a objetos da sus frutos y para muestra un botón:
Estas son las líneas de código del motor isométrico. Cuando hablo de líneas son líneas reales, ni comentarios, ni líneas en blanco, ni delimitadores de ámbito (las llaves), etc:
- Isomot original (escrito en C): 4200 líneas.
- Isomot en C++ (antes): 6000 líneas.
- Isomot en C++ (ahora): 3000 líneas.
Como podéis ver el pulido era más que necesario. El primer diseño aunque funcionaba bien, era bastante malo, con mucho código repetido. Ahora está que da gusto trabajar con él y estoy muy contento.
Perdonad el ladrillo técnico, pero es en lo que estoy volcado desde hace casi tres semanas.