17. Colores en consola

Dentro de poco estaremos empezando a usar el modo gráfico, que dará una apariencia mucho más agradable a la mayoría de juegos. Aun así, para muchos tipos de juegos sencillos el modo texto puede ser suficiente, pero el poder usar colores le daría un poco más de "gracia". Por eso, vamos a ver cómo cambiar el color del texto y el del fondo.

En el "modo texto" (la "consola") de C# tenemos varios colores disponibles. Para ello usaremos el tipo de datos "ConsoleColor", y cambiaremos el color de escritura con "Console.ForegroundColor = ...". Tenemos varios colores prededinidos a partir de su nombre en inglés, como Black, White, Yellow, Red, Blue, DarkRed, Magenta... Así, un ejemplo básico de cómo escribir en colores podría ser:

ConsoleColor miColor;
miColor = ConsoleColor.Red;
 
Console.ForegroundColor = miColor;
Console.Write("Hola");

En nuestro fuente, esto supone 3 cambios:

  • Tendremos un nuevo campo en nuestro "struct", que será el color de cada elemento gráfico.
  • Cuando damos los valores iniciales a nuestros "structs", tendremos que escoger cuál sera el color para ese elemento.
  • Justo antes de "escribir" cada elemento gráfico en pantalla, deberemos cambiar el color de escritura, para que pase a ser al color que tiene ese elemento.

No son grandes cambios. La apariencia del juego podría ser algo como:

Juego03l

Y el fuente podría quedar así:

// Primer mini-esqueleto de juego en modo texto
// Versión "l"
 
using System;
using System.Threading; // Para Thread.Sleep
 
public class Juego03l
{
    struct ElemGrafico {
        public float x;
        public float y;
        public int xInicial;
        public int yInicial;
        public float incrX;
        public float incrY;
        public char simbolo;
        public ConsoleColor color;
        public bool visible;
    }
 
    public static void Main()
    {
        ElemGrafico personaje;
        personaje.xInicial = 40;
        personaje.yInicial = 12;
        personaje.x = personaje.xInicial;
        personaje.y = personaje.yInicial;
        personaje.simbolo = 'A';
        personaje.color = ConsoleColor.Yellow;
 
        int numPremios = 10, numEnemigos = 10, numObstaculos = 20;
 
        // Reservo espacio para los datos repetitivos
        ElemGrafico[] obstaculos = new ElemGrafico[numObstaculos];
        ElemGrafico[] enemigos = new ElemGrafico[numEnemigos];
        ElemGrafico[] premios = new ElemGrafico[numPremios];
 
        int vidas = 3;
        int puntos = 0;
 
        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
        {
            obstaculos[i].x = generador.Next(0,80);
            obstaculos[i].y = generador.Next(1,24);
            obstaculos[i].simbolo = 'o';
            obstaculos[i].color = ConsoleColor.Red;
        }
 
        for (int i=0; i<numEnemigos; i++)  // Enemigos
        {
            enemigos[i].x = generador.Next(0,80);
            enemigos[i].y = generador.Next(1,24);
            enemigos[i].incrX = 0.5f;
            enemigos[i].simbolo = '@';
            enemigos[i].color = ConsoleColor.Blue;
        }
 
        for (int i=0; i<numPremios; i++)  // Premios
        {
            premios[i].x = generador.Next(0,80);
            premios[i].y = generador.Next(1,24);
            premios[i].simbolo = '/';
            premios[i].color = ConsoleColor.White;
            premios[i].visible = true;
        }
 
 
 
        // ------ Bucle de juego ------
        while( ! fin  )
        {
            // -- Dibujar --
            Console.Clear();
 
            // Marcador
            Console.Write("Vidas: {0}  -  Puntos {1}", 
                vidas, puntos);
 
            for (int i=0; i<numObstaculos; i++)  // Obstáculos
            {
                Console.SetCursorPosition(
                    (int) obstaculos[i].x, (int) obstaculos[i].y);
                Console.ForegroundColor =  obstaculos[i].color;
                Console.Write( obstaculos[i].simbolo );
            }
 
            for (int i=0; i<numEnemigos; i++)  // Enemigos
            {
                Console.SetCursorPosition(
                    (int) enemigos[i].x, (int) enemigos[i].y);
                Console.ForegroundColor =  enemigos[i].color;
                Console.Write( enemigos[i].simbolo );
            }
 
            for (int i=0; i<numPremios; i++)  // Premios
            {
                if (premios[i].visible)
                {
                    Console.SetCursorPosition(
                        (int) premios[i].x, (int) premios[i].y);
                    Console.ForegroundColor =  premios[i].color;
                    Console.Write( premios[i].simbolo );
                }
            }
 
            Console.SetCursorPosition(
                (int) personaje.x, (int) personaje.y);
            Console.ForegroundColor =  personaje.color;
            Console.Write( personaje.simbolo );
 
 
            // -- Leer teclas y calcular nueva posición --
            if (Console.KeyAvailable)
            {
                tecla = Console.ReadKey(false);
 
                if(tecla.Key == ConsoleKey.RightArrow) personaje.x++;
                if(tecla.Key == ConsoleKey.LeftArrow) personaje.x--;
                if(tecla.Key == ConsoleKey.DownArrow) personaje.y++;
                if(tecla.Key == ConsoleKey.UpArrow) personaje.y--;
            }
 
            // -- Mover enemigos, entorno --
            for (int i=0; i<numEnemigos; i++)  // Enemigos
            {
                enemigos[i].x = enemigos[i].x + enemigos[i].incrX;
                if (( (int) enemigos[i].x == 0)
                        || ( (int) enemigos[i].x == 79))
                    enemigos[i].incrX = - enemigos[i].incrX;
            }
 
            // -- Colisiones, perder vidas, etc --
            for (int i=0; i<numObstaculos; i++)  // Obstáculos
            {
                if ((obstaculos[i].x == personaje.x)  
                    && (obstaculos[i].y == personaje.y))
                {
                    vidas --;
                    if (vidas == 0)
                        fin=true;
                    personaje.x = personaje.xInicial;
                    personaje.y = personaje.yInicial;
                }
            }
 
            for (int i=0; i<numPremios; i++)  // Obstáculos
            {
                if ((premios[i].x == personaje.x)  
                    && (premios[i].y == personaje.y)
                    && premios[i].visible )
                {
                    puntos += 10;
                    premios[i].visible = false;
                }
            }
 
            for (int i=0; i<numEnemigos; i++)  // Enemigos
            {
                if (( (int) enemigos[i].x == personaje.x)
                        && ( (int) enemigos[i].y == personaje.y))
                {
                    vidas --;
                    if (vidas == 0)
                        fin=true;
                    personaje.x = personaje.xInicial;
                    personaje.y = personaje.yInicial;
                }
            }
 
            // -- Pausa hasta el siguiente "fotograma" del juego --
            Thread.Sleep(40);
        }
    }
}
 

Ejercicio propuesto: Haz que haya enemigos de dos colores distintos y con dos velocidades ligeramente distintas.