38. Varios niveles.
Ahora mismo, tenemos una clase "Nivel", que oculta todos los detalles de la pantalla de juego que estamos recorriendo, y que contiene internamente un array de dos dimensiones para representar las casillas repetitivas de fondo:
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} };
Una primera forma de conseguir que el juego pueda tener varios niveles es convertir ese aray de 2 dimensiones en uno de 3 dimensiones, en el que el primer índice nos permitirá acceder a una pantalla u otra. Como ya existía un método "Avanzar", todos los cambios se podrían hacer dentro de la clase "Nivel", sin que afecte para nada al resto de las clases que forman el juego.
Vamos por partes...
En primer lugar, usaremos un array de tres dimensiones, en vez de uno de dos:
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}, {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,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,1,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,1,1,1,1,1,0,0,0,1,1,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,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,1,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,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,1,1,1,1,1,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,1,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,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1} } };
Que se convertirá en tres pantallas como éstas:
En segundo lugar, la función "Avanzar" deberá cambiar el número de nivel actual (que empezará siendo cero). Deberemos prever que el usuario puede llegar a recorrer todos, y cuando esto ocurra, habrá que dar la partida por terminada o volver al nivel 0. La segunda opción sería simplemente así:
if (nivel < 2) nivel++; else nivel = 0;
Si el método "Dibujar" accediera directamente al array "fondo", ya (casi) habríamos terminado: bastaría cambiar "fondo[fila,columna]" por "fondo[nivel,fila,columna]". Pero nuestro "Dibujar" es así:
public void DibujarOculta() { for (int i = 0; i < elementosFondo; i++) // Imágenes del fondo fondos[i].DibujarOculta(); // ...
Es decir, estamos accediendo a un array auxiliar, formado por "elementos gráficos", que habíamos creado para simplificar las colisiones, así que tendremos que volver a generar ese array. Eso, que antes se hacía dentro del constructor, ahora lo podríamos llevar a una función auxiliar, que se llamara tanto desde el constructor como desde "Avanzar":
public void RellenarArrayDeFondo() { elementosFondo = 0; for (int fila = 0; fila < altoFondo; fila++) // Fondo for (int col = 0; col < anchoFondo; col++) if (fondo[nivel, fila, col] != 0) elementosFondo++; // Y reservo espacio para el array que los contiene fondos = new ElemGrafico[elementosFondo]; int posicFondo = 0; for (int fila = 0; fila < altoFondo; fila++) // Fondo for (int col = 0; col < anchoFondo; col++) if (fondo[nivel, fila, col] != 0) { fondos[posicFondo] = new ElemGrafico("pared.png", anchoCasillaFondo, altoCasillaFondo); fondos[posicFondo].MoverA(margenXFondo + col * anchoCasillaFondo, margenYFondo + fila * altoCasillaFondo); fondos[posicFondo].SetVisible(true); posicFondo++; } }
La clase "Nivel" completa podría quedar así:
/// <summary> /// Nivel: el nivel actual de juego /// @author Nacho Cabanes /// @see Menu Juego /// </summary> /* -------------------------------------------------- Parte de FreddyTwo Versiones hasta la fecha: Num. Fecha Por / Cambios --------------------------------------------------- 0.01 03-Feb-2012 Nacho Cabanes Versión inicial: desglosado a partir de FreddyOne (Juego.cs) 0.02 04-Feb-2012 Cristina Giner Olcina y Jorge Bernabeu Mira Varios niveles consecutivos ---------------------------------------------------- */ using System; // Para Random public class Nivel { // Atributos Random generador; //private int tiempoMax; private int premiosRestantes; private int premiosVisibles, enemigosVisibles, obstaculosVisibles; byte anchoFondo = 24; byte altoFondo = 17; short margenXFondo = 10; byte margenYFondo = 30; byte anchoCasillaFondo = 32; byte altoCasillaFondo = 32; Imagen imgPared; int numPremios, numEnemigos, numObstaculos; Obstaculo[] obstaculos; Enemigo[] enemigos; Premio[] premios; ElemGrafico[] fondos; int elementosFondo; int nivel; 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}, {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,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,1,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,1,1,1,1,1,0,0,0,1,1,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,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,1,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,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,1,1,1,1,1,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,1,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,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1} } }; public Nivel() { numPremios = 20; numEnemigos = 12; numObstaculos = 20; nivel = 0; obstaculos = new Obstaculo[numObstaculos]; enemigos = new Enemigo[numEnemigos]; premios = new Premio[numPremios]; generador = new Random(); // y para cada uno de uno de ellos RellenarArrayDeFondo(); // Preparo elementos for (int i = 0; i < numObstaculos; i++) // Obstaculos { obstaculos[i] = new Obstaculo(); } for (int i = 0; i < numEnemigos; i++) // Enemigos { enemigos[i] = new Enemigo(); } for (int i = 0; i < numPremios; i++) // Premios { premios[i] = new Premio(); } // Al empezar el primer nivel, al menos un precio debe estar visible premios[0].SetVisible(true); premiosRestantes = 1; imgPared = new Imagen("pared.png"); } //funcion auxiliar public void RellenarArrayDeFondo() { elementosFondo = 0; for (int fila = 0; fila < altoFondo; fila++) // Fondo for (int col = 0; col < anchoFondo; col++) if (fondo[nivel, fila, col] != 0) elementosFondo++; // Y reservo espacio para el array que los contiene fondos = new ElemGrafico[elementosFondo]; int posicFondo = 0; for (int fila = 0; fila < altoFondo; fila++) // Fondo for (int col = 0; col < anchoFondo; col++) if (fondo[nivel, fila, col] != 0) { fondos[posicFondo] = new ElemGrafico("pared.png", anchoCasillaFondo, altoCasillaFondo); fondos[posicFondo].MoverA(margenXFondo + col * anchoCasillaFondo, margenYFondo + fila * altoCasillaFondo); fondos[posicFondo].SetVisible(true); posicFondo++; } } /// Deja todo como es necesario para una nueva partida public void Reiniciar() { premiosVisibles = 1; enemigosVisibles = 0; obstaculosVisibles = 0; for (int i = 0; i < numObstaculos; i++) // Obstaculos { obstaculos[i].MoverA(generador.Next(50, 700), generador.Next(30, 550)); obstaculos[i].SetVisible(false); } for (int i = 0; i < numEnemigos; i++) // Enemigos { enemigos[i].MoverA(generador.Next(50, 700), generador.Next(30, 550)); enemigos[i].SetVisible(false); } for (int i = 0; i < numPremios; i++) // Premios { do { premios[i].MoverA(generador.Next(50, 700), generador.Next(30, 550)); premios[i].SetVisible(true); } while (!EsPosibleMover(premios[i].GetX(), premios[i].GetY(), premios[i].GetXFin(), premios[i].GetYFin())); premios[i].SetVisible(false); } // Al empezar el primer nivel, al menos un precio debe estar visible premios[0].SetVisible(true); premiosRestantes = 1; } public void DibujarOculta() { for (int i = 0; i < elementosFondo; i++) // Imágenes del fondo fondos[i].DibujarOculta(); for (int i = 0; i < numObstaculos; i++) // Obstáculos obstaculos[i].DibujarOculta(); for (int i = 0; i < numEnemigos; i++) // Enemigos enemigos[i].DibujarOculta(); for (int i = 0; i < numPremios; i++) // Premios premios[i].DibujarOculta(); } public bool EsPosibleMover(int x, int y, int xFin, int yFin) { // Veo si choca con algún elemento del fondo for (int i = 0; i < elementosFondo; i++) if (fondos[i].ColisionCon(x,y,xFin,yFin)) return false; // Si no ha chocado con ninguno, es posible moverse a esa posición return true; } public int ObtenerPuntosPosicion(int x, int y, int xFin, int yFin) { // Veo si recoge algún premio for (int i = 0; i < numPremios; i++) if (premios[i].ColisionCon(x, y, xFin, yFin)) { premios[i].SetVisible(false); premiosRestantes--; if (premiosRestantes == 0) Avanzar(); return 10; } // O si toca algún obstáculo for (int i = 0; i < numObstaculos; i++) if (obstaculos[i].ColisionCon(x, y, xFin, yFin)) return -1; // O si choca con algún enemigo for (int i = 0; i < numEnemigos; i++) if (enemigos[i].ColisionCon(x, y, xFin, yFin)) return -1; // Si llego hasta aqui, es que no hay puntos que devolver return 0; } public int GetNumEnemigos() { return numEnemigos; } public Enemigo GetEnemigo(int num) { return enemigos[num]; } public void Avanzar() { // Borro la pantalla y aviso del nuevo nivel Hardware.Pausa(200); Hardware.BorrarPantallaOculta(); Hardware.VisualizarOculta(); Hardware.Pausa(1000); // Cambio los "ladrillos" del fondo if (nivel < 2) nivel++; else nivel = 0; RellenarArrayDeFondo(); // Activo un enemigo mas if (enemigosVisibles < numEnemigos) { enemigosVisibles++; for (int i = 0; i < enemigosVisibles; i++) enemigos[i].SetVisible(true); } // Y un obstaculo mas if (obstaculosVisibles < numObstaculos) { obstaculosVisibles++; for (int i = 0; i < obstaculosVisibles; i++) obstaculos[i].SetVisible(true); } // Y un premio mas, y los recoloco if (premiosVisibles < numPremios) { premiosVisibles++; for (int i = 0; i < premiosVisibles; i++) do { premios[i].MoverA(generador.Next(50, 700), generador.Next(30, 550)); premios[i].SetVisible(true); } while (!EsPosibleMover(premios[i].GetX(), premios[i].GetY(), premios[i].GetXFin(), premios[i].GetYFin())); } premiosRestantes = premiosVisibles; } } /* Fin de la clase Nivel */
Ejercicio propuesto: Amplía este fuente para que tenga 5 niveles, en vez de 3.