46. Premios como parte del mapa.

Ahora que nuestro personaje no se mueve libremente por el mapa, sino que tiene que saltar, ya no nos podemos permitir que los premios aparezcan al azar, porque quizá no sean alcanzables.

Una solución sencilla suele ser incluirlos como parte del mapa de fondo, para que su posición esté prefijada. Cuando nuestro personaje toque uno de ellos, podremos eliminarlos del mapa para que no se sigan dibujando.

El mapa podría ser algo como esto:


111111111111111111111111
1            1         1
1            1         1
1       O    1         1
1            1         1
1            2         1
1                  X   1
1                      1
1                111   1
1   E           21 O   1
1                      1
1           22111111   1
1                      1
1        111           1
1   P            O     1
1      21              1
111111111111111111111111

Por ejemplo, en ese mapa, 1 y 2 podrían ser distintos tipos de "ladrillos" de fondo, X podrían ser los premios que hay que recoger, O serían obstáculos mortales, E podría ser la posición inicial de los enemigos, e incluso P podría ser la posición inicial del personaje (que no usaremos todavía en esta entrega).


Los cambios en el fuente serán menos grandes de los que esperamos: ya teníamos un array de elementos de fondo, otro de premios, otro de enemigos... La única diferencia de planteamiento es que antes algunos de ellos tenían tramaño prefijado, mientras que ahora se tendrán que rellenar "al vuelo" a partir de lo que se ha detallado en el mapa.

Como los arrays tienen tamaño prefijado, el primer paso es saber cuál debe ser ese tamaño, para poder reservar espacio, por lo que daremos una primera pasada (en la próxima versión usaremos ArrayList, para evitar esta pasada inicial):

for (int fila = 0; fila < altoFondo; fila++) 
    for (int col = 0; col < anchoFondo; col++)
    {
        // Elementos del fondo: 1 al 9
        if ((fondo[nivel, fila, col] >= '1') && (fondo[nivel, fila, col] <= '9'))
            elementosFondo++;
        // Premios: X
        if (fondo[nivel, fila, col] == 'X')
            numPremios++;
        // Enemigos: E
        if (fondo[nivel, fila, col] == 'E')
            numEnemigos++;
        // Obstáculos: O
        if (fondo[nivel, fila, col] == 'O')
            numObstaculos++;
        ...

Y en una segunda pasada, tras reservar espacio, rellenaremos los arrays:

 
// Y reservo espacio para el array que los contiene
fondos = new ElemGrafico[elementosFondo];
obstaculos = new Obstaculo[numObstaculos];
enemigos = new Enemigo[numEnemigos];
premios = new Premio[numPremios];
 
int posicFondo = 0, contEnemigos = 0, contObstaculos = 0, contPremios = 0;
for (int fila = 0; fila < altoFondo; fila++)  // Fondo
    for (int col = 0; col < anchoFondo; col++)
        switch (fondo[nivel, fila, col])
        {
            case '1':
                fondos[posicFondo] = new ElemGrafico("pared.png", anchoCasillaFondo, altoCasillaFondo);
                fondos[posicFondo].MoverA(margenXFondo + col * anchoCasillaFondo,
                    margenYFondo + fila * altoCasillaFondo);
                fondos[posicFondo].SetVisible(true);
                posicFondo++;
                break;
            case '3':
                fondos[posicFondo] = new ElemGrafico("pared3.png", anchoCasillaFondo, altoCasillaFondo);
                fondos[posicFondo].MoverA(margenXFondo + col * anchoCasillaFondo,
                    margenYFondo + fila * altoCasillaFondo);
                fondos[posicFondo].SetVisible(true);
                posicFondo++;
                break;
            case 'X':
                premios[contPremios] = new Premio();
                premios[contPremios].MoverA(margenXFondo + col * anchoCasillaFondo,
                    margenYFondo + fila * altoCasillaFondo);
                premios[contPremios].SetVisible(true);
                contPremios++;
                break;
        ...

Y a la hora de reiniciar, ya no habrá que colocarlos en posiciones al azar, sino volver a tomar los datos que preveía el mapa:

public void Reiniciar()
{
    nivel = 0;
    RellenarArrayDeFondo();
}

Las rutinas de dibujado, de comprobación de colisiones, etc. no deberían necesitar cambios.

Si "te atascas" intentando implementar estos cambios, aquí tienes la "versión oficial", con fuentes y ejecutable.

Ejercicio propuesto: Usa "ArrayList" en vez de arrays, para no tener que dar dos pasadas.