Por Nacho Cabanes
Ahora mismo, cuando se acaban las 5 vidas o cuando se pulsa ESC, se marca la partida como "partidaTerminada=true", termina el juego y se vuelve al sistema operativo.
Ahora queremos que cuando se acaban las vidas o se pulse ESC, se vuelva a la pantalla d presentación, se pueda comenzar una nueva partida, en las condiciones iniciales: otra vez 5 vidas, 0 puntos, el personaje en la casilla inicial...
Basta con que "Main" no llame una única vez al "buclePrincipal" del juego, sino que lo haga de forma repetitiva, según si ha terminado o no la sesión de juego, algo que dependería de la tecla que pulse el usuario cuando está en la pantalla de presentación:
public static void Main() { inicializar(); do { mostrarPresentacion(); if (!sesionTerminada) { inicializarPartida(); buclePrincipal(); } } while (!sesionTerminada); }
Por tanto, la pantalla de presentación debería permitir escoger entre la tecla de comenzar una nueva partida o la tecla de abandonar toda la sesión de juego:
static void mostrarPresentacion() { //dibujo la presentacion presentacion.DibujarOculta(); // Esscribo avisos de las teclas utilizables Hardware.EscribirTextoOculta( "Pulsa Espacio para jugar", 300, 550, 0xAA, 0xAA, 0xAA, fuente18); Hardware.EscribirTextoOculta( "o pulsa T para terminar", 300, 575, 0xAA, 0xAA, 0xAA, fuente18); // Finalmente, muestro en pantalla Hardware.VisualizarOculta(); //hasta que se pulse espacio do { } while ((! Hardware.TeclaPulsada(Hardware.TECLA_ESP) ) && (! Hardware.TeclaPulsada(Hardware.TECLA_T))); if (Hardware.TeclaPulsada(Hardware.TECLA_T)) sesionTerminada = true; //borro la presentacion Hardware.BorrarPantallaOculta(0,0,0); }
Y además, necesitamos la función auxiliar "inicializarPartida" , que se encargue de volver a dejar el personaje con 5 vidas, 0 puntos y en su posición inicial:
static void inicializarPartida() { vidas = 5; puntos = 0; // Coloco al personaje x = 1; y = 1; filaHabitacion = 0; columnaHabitacion = 0; colocarEnemigo(); // Y al enemigo en posición al azar partidaTerminada = false; vidas++; morir(); // Para que aparezca el aviso de que empieza con 5 vidas }
El conjunto del fuente podría ser así:
/** * Juego: Logica de juego * * @see Hardware * @author 1-DAI IES San Vicente 2009/10 */ /* -------------------------------------------------- Parte de Death Pit - Remake Versiones hasta la fecha: Num. Fecha Por / Cambios --------------------------------------------------- 0.01 08-Sep-2009 Nacho Cabanes Version inicial: muestra una imagen 0.02 07-Oct-2009 Nacho Cabanes Mueve el personaje hacia la derecha hasta llegar al margen 0.03 13-Oct-2009 Nacho Cabanes El personaje se mueve con flechas Un primer enemigo que se mueve a la vez 0.04 16-Oct-2009 Nacho Cabanes Primera pantalla de presentacion El primer enemigo rebota en los lados Un segundo enemigo nos persigue 0.05 20-Oct-2009 Nacho Cabanes Array de enemigos (murcielagos) que rebotan en los lados 0.06 28-Oct-2009 Nacho Cabanes Array bidimensional para imagen de fondo 0.07 04-Nov-2009 Nacho Cabanes El personaje se mueve solo por los "huecos" Eliminados los enemigos (por ahora) Renombradas variables i,j a fila,colum 0.08 10-Nov-2009 Nacho Cabanes Varias funciones para que el fuente sea mas modular 0.09 16-Nov-2009 Nacho Cabanes Varias pantallas conectadas 0.10 24-Nov-2009 Nacho Cabanes Un enemigo que se mueve "por los huecos" 0.11 02-Dic-2009 Nacho Cabanes Si chocamos con enemigo perdemos una vida 0.12 04-Dic-2009 Nacho Cabanes El personaje cambia de imagen según la dirección Si choco con un enemigo de lado, muere él y me da puntos 0.13 11-Dic-2009 Joaquín, Alejandro, Miguel; retoques por Nacho Cuando acaban las vidas o se pulsa ESC, acaba la partida, se vuelve a la presentación y se puede volver a empezar ---------------------------------------------------- */ using System; // Para numeros aleatorios: System.Random public class Juego { // Variables que usaremos: una imagen y un tipo de letra static ElemGrafico imagenPersonaje,imagenEnemigo, presentacion; static ElemGrafico imagenPersonajeD, imagenPersonajeI, imagenPersonajeA; static ElemGrafico imagenFondoHoriz,imagenFondoHorizAcido, imagenFondoVert, imagenEscalera; static Fuente fuente18; static int fila, colum; // Para recorrer static short x=1, y=1; static short xEnemigo=1, yEnemigo=1; static short incrXEnemigo=1, incrYEnemigo=0; static short contadorFotogramasEnemigo = 0; static short pausaFotogramasEnemigo = 10; static short minX = 0, maxX = 6, minY = 0, maxY = 6; // Tamaño de cada pantalla de juego static int filasPantalla = 7; static int columnasPantalla = 7; // Situación de la pantalla actual dentro del mapa de habitaciones static int filaHabitacion = 0; static int columnaHabitacion = 0; // Vidas en cada partida static int vidas = 5; static int puntos = 0; const int DERECHA = 0; const int IZQUIERDA = 1; const int ARRIBA = 2; const int ABAJO = 3; static int direccion = DERECHA; static Random numAleatorio; // Para que el enemigo se mueva al azar static int[,,,] mapa = { // Comienzo del mapa de casillas { // Primera fila de habitaciones { // Habitacion (0,0) {1,2,1,1,1,2,1}, {3,0,0,0,0,0,0}, {3,4,3,4,3,1,1}, {3,4,0,4,0,0,0}, {3,4,3,4,3,4,3}, {3,4,0,0,0,4,3}, {3,1,1,4,1,4,3} }, { // Habitacion (0,1) {1,2,1,1,1,2,1}, {0,0,0,0,0,0,3}, {1,1,3,4,3,4,3}, {0,0,3,4,3,4,3}, {3,4,3,4,3,4,3}, {3,4,3,4,3,4,3}, {3,1,3,4,3,4,3} }, }, { // Segunda fila de habitaciones { // Habitacion (1,0) {3,2,1,4,1,4,1}, {3,0,0,0,0,0,0}, {3,1,1,4,3,1,1}, {3,0,0,4,3,0,0}, {3,4,3,4,3,4,3}, {3,4,3,4,0,4,3}, {1,1,1,1,1,1,3} }, { // Habitacion (1,1) {1,2,1,4,1,4,1}, {0,0,0,0,0,0,3}, {1,1,1,4,1,1,3}, {0,0,0,4,0,0,3}, {1,4,3,4,3,4,3}, {3,4,3,4,0,4,3}, {1,1,1,1,1,1,3} }, }, }; static bool partidaTerminada; // Si ha terminado una partida puntual static bool sesionTerminada; // Si ha terminado una sesion completa de juego // Inicialización al comenzar la sesión de juego static void inicializar() { // Inicializo modo grafico 800x600 puntos, 24 bits de color Hardware.Inicializar(800, 600, 24); // Cargo imagenes y tipos de letra imagenPersonaje = new ElemGrafico("imagenes/personaje.png"); imagenEnemigo = new ElemGrafico("imagenes/escorpion.png"); imagenPersonajeD = new ElemGrafico("imagenes/personajed1.png"); imagenPersonajeI = new ElemGrafico("imagenes/personajei1.png"); imagenPersonajeA = new ElemGrafico("imagenes/personajea1.png"); imagenFondoHoriz = new ElemGrafico("imagenes/fondo1.png"); imagenFondoHorizAcido = new ElemGrafico("imagenes/fondo2.png"); imagenFondoVert = new ElemGrafico("imagenes/fondo3.png"); imagenEscalera = new ElemGrafico("imagenes/escalera.png"); fuente18 = new Fuente("FreeSansBold.ttf", 18); presentacion = new ElemGrafico("imagenes/present.png"); // Para que el enemigo se mueva al azar numAleatorio = new Random( DateTime.Now.Millisecond ); sesionTerminada = false; } // --- Comienzo de un nueva partida: reiniciar variable --- static void inicializarPartida() { vidas = 5; puntos = 0; // Coloco al personaje x = 1; y = 1; filaHabitacion = 0; columnaHabitacion = 0; colocarEnemigo(); // Y al enemigo en posición al azar partidaTerminada = false; vidas++; morir(); // Para que aparezca el aviso de que empieza con 5 vidas } // --- Mostrar pantalla de presentación --- static void mostrarPresentacion() { //dibujo la presentacion presentacion.DibujarOculta(); // Esscribo avisos de las teclas utilizables Hardware.EscribirTextoOculta( "Pulsa Espacio para jugar", 300, 550, 0xAA, 0xAA, 0xAA, fuente18); Hardware.EscribirTextoOculta( "o pulsa T para terminar", 300, 575, 0xAA, 0xAA, 0xAA, fuente18); // Finalmente, muestro en pantalla Hardware.VisualizarOculta(); //hasta que se pulse espacio do { } while ((! Hardware.TeclaPulsada(Hardware.TECLA_ESP) ) && (! Hardware.TeclaPulsada(Hardware.TECLA_T))); if (Hardware.TeclaPulsada(Hardware.TECLA_T)) sesionTerminada = true; //borro la presentacion Hardware.BorrarPantallaOculta(0,0,0); } // --- Coloca el enemigo en cualquier posición "libre" de la pantalla actual ----- static void comprobarTeclas() { // Muevo si se pulsa alguna flecha del teclado if (Hardware.TeclaPulsada(Hardware.TECLA_DER) ) { imagenPersonaje = imagenPersonajeD; direccion = DERECHA; if (x == maxX) { x = 0; columnaHabitacion++; colocarEnemigo(); } else if (x < maxX) if ((mapa[filaHabitacion, columnaHabitacion, y,x+1] == 0) // Espacio en blanco || (mapa[filaHabitacion, columnaHabitacion, y,x+1] == 4) )// Escalera x++; } if(Hardware.TeclaPulsada(Hardware.TECLA_ARR) ) { imagenPersonaje = imagenPersonajeA; direccion = ARRIBA; if (y == 0) { y = maxY; filaHabitacion--; colocarEnemigo(); } else if ( y > 0) if ((mapa[filaHabitacion, columnaHabitacion, y-1,x] == 0) // Espacio en blanco || (mapa[filaHabitacion, columnaHabitacion, y-1,x] == 4) )// Escalera y--; } if (Hardware.TeclaPulsada(Hardware.TECLA_IZQ) ) { imagenPersonaje = imagenPersonajeI; direccion = IZQUIERDA; if (x == 0) { x = maxX; columnaHabitacion--; colocarEnemigo(); } else if ( x > 0) if ((mapa[filaHabitacion, columnaHabitacion, y,x-1] == 0) // Espacio en blanco || (mapa[filaHabitacion, columnaHabitacion, y,x-1] == 4) )// Escalera x--; } if (Hardware.TeclaPulsada(Hardware.TECLA_ABA) ) { imagenPersonaje = imagenPersonajeA; direccion = ABAJO; if (y == maxY) { y = 0; filaHabitacion++; colocarEnemigo(); } else if (y < maxY) if ((mapa[filaHabitacion, columnaHabitacion, y+1,x] == 0) // Espacio en blanco || (mapa[filaHabitacion, columnaHabitacion, y+1,x] == 4) )// Escalera y++; } if (Hardware.TeclaPulsada(Hardware.TECLA_ESC)) partidaTerminada = true; } // --- Coloca el enemigo en cualquier posición "libre" de la pantalla actual ----- static void colocarEnemigo() { do { xEnemigo = (short) (numAleatorio.Next(0,columnasPantalla-2)+1); yEnemigo = (short) (numAleatorio.Next(0,filasPantalla-2)+1); } while ((mapa[filaHabitacion, columnaHabitacion, yEnemigo,xEnemigo] != 0) // Espacio en blanco && (mapa[filaHabitacion, columnaHabitacion, yEnemigo,xEnemigo] != 4)); // Escalera } // --- Animación de los enemigos y demás objetos "que se muevan solos" ----- static void moverElementos() { // El enemigo solo se mueve un fotograma de cada varios contadorFotogramasEnemigo ++; if (contadorFotogramasEnemigo == pausaFotogramasEnemigo) { contadorFotogramasEnemigo = 0; xEnemigo += incrXEnemigo; yEnemigo += incrYEnemigo; } // Para la siguiente posición, escojo al azar y miro si realmente se puede mover bool posibleMover = false; do { int numeroAzar = (int) numAleatorio.Next(0,100); if (numeroAzar < 25) // Intento derecha { if ((xEnemigo < maxX) && // Si no ha llegado al borde ((mapa[filaHabitacion, columnaHabitacion, yEnemigo,xEnemigo+1] == 0) // Espacio en blanco || (mapa[filaHabitacion, columnaHabitacion, yEnemigo,xEnemigo+1] == 4)) )// Escalera { incrXEnemigo = 1; incrYEnemigo = 0; posibleMover = true; } } else if (numeroAzar < 50) // Intento izquierda { if ((xEnemigo > 0) && // Si no ha llegado al borde ((mapa[filaHabitacion, columnaHabitacion, yEnemigo,xEnemigo-1] == 0) // Espacio en blanco || (mapa[filaHabitacion, columnaHabitacion, yEnemigo,xEnemigo-1] == 4)) )// Escalera { incrXEnemigo = -1; incrYEnemigo = 0; posibleMover = true; } } else if (numeroAzar < 75) // Intento arriba { if ((yEnemigo > 0) && // Si no ha llegado al borde ((mapa[filaHabitacion, columnaHabitacion, yEnemigo-1,xEnemigo] == 0) // Espacio en blanco || (mapa[filaHabitacion, columnaHabitacion, yEnemigo-1,xEnemigo] == 4)) )// Escalera { incrXEnemigo = 0; incrYEnemigo = -1; posibleMover = true; } } else // Intento abajo { if ((yEnemigo < maxY) && // Si no ha llegado al borde ((mapa[filaHabitacion, columnaHabitacion, yEnemigo+1,xEnemigo] == 0) // Espacio en blanco || (mapa[filaHabitacion, columnaHabitacion, yEnemigo+1,xEnemigo] == 4)) )// Escalera { incrXEnemigo = 0; incrYEnemigo = 1; posibleMover = true; } } } while (! posibleMover); } // --- Comprobar colisiones de enemigo con personaje, etc --- static void comprobarColisiones() { if ((x==xEnemigo) && (y==yEnemigo)) { if ((direccion == DERECHA) || (direccion == IZQUIERDA)) matarEnemigo(); else morir(); } } // --- Matar enemigo: aumentar puntos y recolocarlo --- static void matarEnemigo() { puntos += 10; colocarEnemigo(); } // --- Morir personaje: mostrar vidas restantes, etc --- static void morir() { int i; vidas --; // Rectángulo verde Hardware.RectanguloRellenoRGBA( 0,0,490,350, // Posicion, ancho y alto de la pantalla 0,255,0, // En color verde 200); // Con algo de transparencia // Dibujo las vidas restantes Hardware.EscribirTextoOculta( "Te quedan", 250, 100, 0, 0, 0, fuente18); Hardware.EscribirTextoOculta( vidas.ToString(), 250, 150, 0xFF, 0, 0, fuente18); Hardware.EscribirTextoOculta( "vidas", 250, 200, 0, 0, 0, fuente18); for (i=0; i<vidas; i++) { imagenPersonaje.MoverA( 130 , (short) (50+ i*50) ); imagenPersonaje.DibujarOculta(); } // Aviso de la tecla para volver Hardware.EscribirTextoOculta( "Pulsa V para volver al juego", 120, 350, 0xAA, 0xAA, 0xAA, fuente18); // Y quito el aviso de "ESC para salir" Hardware.RectanguloRellenoRGBA( 160, 370, 600,550, 0,0,0, 255); // Finalmente, muestro en pantalla Hardware.VisualizarOculta(); // Espero hasta que se pulse la tecla de volver do { } while (! Hardware.TeclaPulsada(Hardware.TECLA_V) ); // Vuelvo a colocar el enemigo al azar colocarEnemigo(); // Si no hay vidas, se acabó la partida if (vidas == 0) partidaTerminada = true; } // --- Dibujar en pantalla todos los elementos visibles del juego --- static void dibujarElementos() { Hardware.BorrarPantallaOculta(0,0,0); // Dibujo el fondo de la pantalla for (fila=0; fila<filasPantalla; fila++) for (colum=0; colum<columnasPantalla; colum++) switch (mapa[filaHabitacion, columnaHabitacion, fila,colum]) { case 0: // Espacio en blanco, no dibujo nada break; case 1: imagenFondoHoriz.MoverA( (short) (colum*70) , (short) (fila*50)); imagenFondoHoriz.DibujarOculta(); break; case 2: imagenFondoHorizAcido.MoverA( (short) (colum*70) , (short) (fila*50)); imagenFondoHorizAcido.DibujarOculta(); break; case 3: imagenFondoVert.MoverA( (short) (colum*70) , (short) (fila*50)); imagenFondoVert.DibujarOculta(); break; case 4: imagenEscalera.MoverA( (short) (colum*70) , (short) (fila*50)); imagenEscalera.DibujarOculta(); break; } // Dibujo el personaje, el enemigo y un texto en la pantalla oculta imagenPersonaje.MoverA( (short) (x*70) , (short) (y*50) ); imagenPersonaje.DibujarOculta(); imagenEnemigo.MoverA( (short) (xEnemigo*70) , (short) (yEnemigo*50) ); imagenEnemigo.DibujarOculta(); Hardware.EscribirTextoOculta( "Puntos", 600, 100, 0xAA, 0xAA, 0xAA, fuente18); Hardware.EscribirTextoOculta( puntos.ToString(), 600, 140, 0xAA, 0xAA, 0xAA, fuente18); Hardware.EscribirTextoOculta( "Pulsa ESC para salir", 170, 380, 0xAA, 0xAA, 0xAA, fuente18); // Finalmente, muestro en pantalla Hardware.VisualizarOculta(); } // --- Pausa tras cada fotograma de juego, para velocidad de 25 fps ----- static void pausaFotograma() { Hardware.Pausa( 40 ); } // --- Bucle principal de juego ----- static void buclePrincipal() { do { comprobarTeclas(); moverElementos(); comprobarColisiones(); dibujarElementos(); pausaFotograma(); } while (! partidaTerminada); } // --- Cuerpo del programa ----- public static void Main() { inicializar(); do { mostrarPresentacion(); if (!sesionTerminada) { inicializarPartida(); buclePrincipal(); } } while (!sesionTerminada); } } /* fin de la clase Juego */
Si prefieres descargar todo el paquete, incluyendo el ejecutable (en la carpeta BIN/DEBUG), las imágenes, y un proyecto para poder recompilar usando SharpDevelop, aquí lo tienes todo en un fichero ZIP de tamaño cercano a 1 Mb.
Siguiente entrega...