13. Pequeñas mejoras
Antes de seguir añadiendo nuevas funcionalidades, vamos a tomarnos un momento para mejorar un poco lo que tenemos hasta ahora:
- Tenemos 3 obstáculos. Vamos a incluirlos en un nuevo array, y de paso, podemos aumentar su cantidad a 20.
- Sólo hay un enemigo. Vamos a ampliarlo también, para que pasen a ser 10 (nuevamente, usando arrays)
- Vamos a hacer que la cantidad de obstáculos, premios y enemigos esté en variables, en vez de prefijado en "números mágicos", para que el programa sea más legible, más fácil de modificar y menos propenso a errores.
- Cuando nuestro personaje pasa por un sitio en el que hay un "premio", deja de verse en pantalla. Más adelante haremos que pueda "recoger" los premios, pero de momento haremos que al menos se vea al personaje, en vez de al premio.
- Vamos a hacer que la condición de fin de partida no sea "1 o 0" sino "verdadero o falso".
Vamos con ello...
Eso de que la condición de fin de partida sea "verdadero" o "falso" supone que la variable "fin" ya no será un número entero, sino un dato "booleano". Tendrá el valor inicial "false" (porque inicialmente no ha terminado la partida), pasará a ser "true" cuando choquemos con algo (porque entonces sí deberá finalizar la partida), y el juego se repetirá mientras no llegue el fin:
bool fin = false; ... while ( ! fin ) { ...
Lo de añadir un array para los obstáculos no debería ser difícil. La única complicación que añade es la de que ahora la comprobación de colisiones habrá que hacerla de forma repetitiva, por ejemplo con un "for":
for (int i=0; i<20; i++) // Obstáculos { if ((xObstaculo[i] == x) && (yObstaculo[i] == y)) chocadoObstaculo = true; }
Si queremos que la cantidad de obstáculos (y la de premios, y la de enemigos) estén en variables, los cambios no son grandes:
int numObstaculos = 20; int[] xObstaculo = new int[numObstaculos]; ... for (int i=0; i<numObstaculos; i++) // Obstáculos { if ((xObstaculo[i] == x) && (yObstaculo[i] == y)) chocadoObstaculo = true; }
Con relación a los enemigos, sólo hay un detalle adicional a tener en cuenta: no deberíamos comparar sus coordenadas directamente, porque son "float", de modo que puede ocurrir que nuestro personaje se encuentre en la posición 50 y un enemigo en la 50.2, que corresponden a la misma posición en pantalla, pero son distintas coordenadas, de modo que no se detectaría como una colisión. Por eso, deberemos convertir sus coordenadas a entero, antes de comparar con la posición del enemigo o con los márgenes de la pantalla:
if (( (int) xEnemigo[i] == x) && ( (int) yEnemigo[i] == y)) fin = true;
El resultado, en pantalla, podría ser algo como:
Y todo el fuente junto se podría convertir en:
// Primer mini-esqueleto de juego en modo texto // Versión "h" using System; using System.Threading; // Para Thread.Sleep public class Juego03h { public static void Main() { int x = 40, y=12; // 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(0,24); } for (int i=0; i<numEnemigos; i++) // Enemigos { xEnemigo[i] = generador.Next(0,80); yEnemigo[i] = generador.Next(0,24); incr[i] = 0.5f; } for (int i=0; i<numPremios; i++) // Premios { xPremio[i] = generador.Next(0,80); yPremio[i] = generador.Next(0,24); } // ------ Bucle de juego ------ while( ! fin ) { // -- Dibujar -- Console.Clear(); 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)) fin = true; } for (int i=0; i<numEnemigos; i++) // Enemigos { if (( (int) xEnemigo[i] == x) && ( (int) yEnemigo[i] == y)) fin = true; } // -- Pausa hasta el siguiente "fotograma" del juego -- Thread.Sleep(40); } } }
Ejercicio propuesto: Haz que los enemigos no puedan aparecer en la misma fila que el personaje, para evitar que se pueda acabar la partida demasiado pronto.