14. Varias vidas

Ahora vamos a hacer que nuestro personaje comience la partida con 3 vidas, y que cada vez que toque un obstáculo o un enemigo pierda una de esas vidas. Cuando llegue a 0 vidas, terminará la partida.

Los cambios serán:

  • Añadir un contador de vidas
  • Mostrar un marcador, dejando hueco para él (no deberemos mostrar obstáculos, premios ni enemigos en la primera fila de pantalla)
  • Cuando haya una colisión (con un obstáculo o un enemigo), todavía no debe acabar la partida. Deberemos restar una vida y comprobar si es la última (empezaremos con 3). Si es la última, terminará el juego, pero si no lo era, habrá que recolocar el personaje en su posición inicial, para que no pierda varias vidas seguidas (porque en el siguiente fotograma seguiría chocando con el mismo obstáculo o quizá incluso con el mismo personaje móvil que provocó que perdiéramos una vida).

Veamos cómo hacerlo...

El contador de vidas es trivial, una nueva variable entera:

int vidas = 3;

Escribir el marcador no es mucho más difícil: un Write. Si lo hacemos justo después de borrar la pantalla, se escribirá en la posición (0,0), sin necesidad de un SetCursorPosition:

Console.Clear();
Console.Write("Vidas: {0}", vidas);

Dejar hueco para el marcador apenas es un poco más difícil: cuando generamos coordenadas al azar, no permitiremos que Y valga 0, de modo que la primera fila quede libre:

xPremio[i] = generador.Next(0,80);
yPremio[i] = generador.Next(1,24);

Y lo de que las colisiones supongan perder sólo una vida (pero quizá no acabar la partida) y recolocar el personaje, también será sencillo:

if (( (int) xEnemigo[i] == x)  && ( (int) yEnemigo[i] == y))
{
    vidas --;
    if (vidas == 0)
        fin=true;
    x = xInicial;
    y = yInicial;
}

Lo que supone que será necesario declarar esas nuevas variables auxiliares "xInicial" e "yInicial" al principio el programa:

int xInicial = 40, yInicial = 12;
int x=xInicial, y=yInicial; // Posición del personaje
 

El fuente completo sería:

// Primer mini-esqueleto de juego en modo texto
// Versión "i"
 
using System;
using System.Threading; // Para Thread.Sleep
 
public class Juego03i
{
    public static void Main()
    {
        int vidas = 3;
        int xInicial = 40, yInicial = 12;
        int x=xInicial, y=yInicial; // Posición del personaje
 
        int numPremios = 10, numEnemigos = 10, numObstaculos = 20;
 
        // Reservo espacio para los datos repetitivos
        int[] xObstaculo = new int[numObstaculos]; // Obstáculos
        int[] yObstaculo = new int[numObstaculos];
 
        float[] xEnemigo = new float[numEnemigos]; // Enemigos
        float[] yEnemigo = new float[numEnemigos];
        float[] incr  = new float[numEnemigos];
 
        int[] xPremio = new int[numPremios]; // Premios
        int[] yPremio = new int[numPremios];
 
        bool fin = false;
        ConsoleKeyInfo tecla;  // Tecla pulsada
 
        // Genero las posiciones de los elementos al azar
        Random generador = new Random();
        for (int i=0; i<numObstaculos; i++)  // Obstaculos
        {
            xObstaculo[i] = generador.Next(0,80);
            yObstaculo[i] = generador.Next(1,24);
        }
        for (int i=0; i<numEnemigos; i++)  // Enemigos
        {
            xEnemigo[i] = generador.Next(0,80);
            yEnemigo[i] = generador.Next(1,24);
            incr[i] = 0.5f;
        }
        for (int i=0; i<numPremios; i++)  // Premios
        {
            xPremio[i] = generador.Next(0,80);
            yPremio[i] = generador.Next(1,24);
        }
 
 
 
        // ------ Bucle de juego ------
        while( ! fin  )
        {
            // -- Dibujar --
            Console.Clear();
 
            // Marcador
            Console.Write("Vidas: {0}", vidas);
 
            for (int i=0; i<numObstaculos; i++)  // Obstáculos
            {
                Console.SetCursorPosition(
                    xObstaculo[i], yObstaculo[i]);
                Console.Write("o");
            }
 
            for (int i=0; i<numEnemigos; i++)  // Enemigos
            {
                Console.SetCursorPosition(
                    (int) xEnemigo[i], (int) yEnemigo[i]);
                Console.Write("@");
            }
 
            for (int i=0; i<numPremios; i++)  // Premios
            {
                Console.SetCursorPosition(xPremio[i], yPremio[i]);
                Console.Write("/");
            }
 
            Console.SetCursorPosition(x, y);
            Console.Write("A");
 
 
            // -- Leer teclas y calcular nueva posición --
            if (Console.KeyAvailable)
            {
                tecla = Console.ReadKey(false);
 
                if(tecla.Key == ConsoleKey.RightArrow) x++;
                if(tecla.Key == ConsoleKey.LeftArrow) x--;
                if(tecla.Key == ConsoleKey.DownArrow) y++;
                if(tecla.Key == ConsoleKey.UpArrow) y--;
            }
 
            // -- Mover enemigos, entorno --
            for (int i=0; i<numEnemigos; i++)  // Enemigos
            {
                xEnemigo[i] = xEnemigo[i] + incr[i];
                if (( (int) xEnemigo[i] == 0)
                        || ( (int) xEnemigo[i] == 79))
                    incr[i] = - incr[i];
            }
 
            // -- Colisiones, perder vidas, etc --
            for (int i=0; i<numObstaculos; i++)  // Obstáculos
            {
                if ((xObstaculo[i] == x)  
                    && (yObstaculo[i] == y))
                {
                    vidas --;
                    if (vidas == 0)
                        fin=true;
                    x = xInicial;
                    y = yInicial;
                }
            }
 
            for (int i=0; i<numEnemigos; i++)  // Enemigos
            {
                if (( (int) xEnemigo[i] == x)
                        && ( (int) yEnemigo[i] == y))
                {
                    vidas --;
                    if (vidas == 0)
                        fin=true;
                    x = xInicial;
                    y = yInicial;
                }
            }
 
            // -- Pausa hasta el siguiente "fotograma" del juego --
            Thread.Sleep(40);
        }
    }
}
 

Ejercicio propuesto: Haz que los obstáculos no puedan aparecer en la misma posición que el personaje, para evitar que la partida acabe de forma prematura y sin motivo aparente.