42. Leer niveles desde fichero.

Hasta ahora, la descripción de los niveles que recorreremos en el juego se hace mediante un array, prefijado en el código fuente:

public byte[,,] fondo =
{
    {
        {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
        {1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
        {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
    },
    {
        {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
        {1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1},
        ...

Ahora vamos a llevarlo a un fichero, como forma de que el juego se pueda ampliar sin necesidad de tocar el código. El primer paso será volcar a un fichero el contenido de este array. Para ello, tenemos que escoger un formato. Por ejemplo, podríamos usar un fichero de texto, en el que cada bloque de varias líneas represente un nivel: una cantidad predefinida de líneas, cada una con una cantidad de letras prefijada. Para mayor legibilidad, podemos incluir una línea en blanco entre un nivel y otro. Y para que nos sea sencillo de manipular, podemos incluir una primera línea que nos diga la cantidad de niveles que contiene el fichero:


3

111111111111111111111111
100000000000010000000001
100000000000010000000001
100000000000010000000001
100000000000010000000001
100000000000010000000001
100000000000000000000001
100000000000000000000001
100000000000000000000001
100000000000000000000001
100000000000000000000001
100000000000111111110001
100000000000000000000001
100000000000000000000001
100000000000000000000001
100000000000000000000001
111111111111111111111111

111111111111111111111111
100000000000010000000001
100000000000010000000001
100001000000010000000001
...

Ahora podemos crear una función encargada de leer ese fichero, y rellenar con él los datos del array:

 
private void leerDesdeFichero()
{
    StreamReader ficheroMapas = File.OpenText("niveles.dat");
    string linea;
 
    linea = ficheroMapas.ReadLine();
    int numeroNiveles = Convert.ToInt32(linea);
 
    fondo = new byte[numeroNiveles, altoFondo, anchoFondo];
 
    for (int nivelActual = 0; nivelActual < numeroNiveles; nivelActual++)
    {
        string separador = ficheroMapas.ReadLine();
 
        for (int lineaActual = 0; lineaActual < altoFondo; lineaActual++)
        {
            linea = ficheroMapas.ReadLine();
            for (int columnaActual = 0; columnaActual < anchoFondo; columnaActual++)
                fondo [nivelActual, lineaActual, columnaActual] = 
                    Convert.ToByte(linea[columnaActual]-48);
        }
    }
    ficheroMapas.Close();
}

Sólo queda un cambio por hacer: dejar el array vacío y hacer que el constructor comience leyendo los datos desde fichero:

public byte[, ,] fondo;
 
public Nivel()
{
    leerDesdeFichero();
 
    numPremios = 20;
    ...

Si nos molesta eso de que cualquiera pueda modificar el fichero, hay una alternativa sencilla: encriptarlo. El método "leerDesdeFichero" debería ir desencriptando los datos a medida que los lee, y podríamos crear una utilidad adicional que tomase un fichero "legible" (creado con cualquier editor de texto) y lo encriptara, para dificultar su modificación por terceras personas.

Podemos aprovechar para que el fichero guarde información extra, como la posición inicial de nuestro personaje, o la cantidad de enemigos y sus posiciones. Pero eso lo haremos un poco más adelante...

Ejercicio propuesto: Amplía el juego con dos niveles más, hasta llegar a un total de cinco, y comprueba que se comportan correctamente.