11. Ajustando la velocidad.

Ahora mismo, el personaje y el enemigo se mueven a la misma velocidad. Generalmente, eso no es lo más deseable para la jugabilidad. Suele ser preferible que se puedan mover a velocidad distinta, típicamente algo mayor para el personaje, de modo que "tengamos alguna posibilidad de escapar".

Por ejemplo, si queremos que nuestro personaje vaya al doble de velocidad que el enemigo, lo podemos hacer cambiando uno de los "incrementos" de su movimiento (que equivalen a la velocidad de cada uno de ellos).

Una posibilidad es que la velocidad del enemigo sea 1 ("incr1 = 1;") y que la velocidad de nuestro personaje sea 2 ("if(tecla.Key == ConsoleKey.RightArrow) x=x+2;"). La otra alternativa es que nuestro personaje se mueva de uno en uno, y que el enemigo lo haga "de media casilla en media casilla".

La primera alternativa (mover de 2 en 2) supone perder precisión de movimiento, y estamos trabajando en "modo texto", que ya de por sí supone poca precisión en pantalla. La segunda alternativa no supone perder precisión de movimiento (aunque cuando su x sea 2.5 no se verá ninguna diferencia con cuando x sea 2), y además permitirá practicar el uso de números con decimales, así que vamos a optar por esta segunda opción.

Ahora, la X, la Y y la velocidad del enemigo serán números reales:

float xe1 = 10, ye1 = 10, incr1 = 0.5f;

Pero al colocarnos en pantalla tendremos que "quitar los decimales", porque "SetCursorPosition" necesita trabajar con números enteros. La forma más simple es hacer una "conversión de tipos", poniendo "(int)" antes de las coordenadas:

Console.SetCursorPosition((int) xe1, (int) ye1);

El resultado sería:

// Primer mini-esqueleto de juego en modo texto
// Versión "f"
 
using System;
using System.Threading; // Para Thread.Sleep
 
public class Juego03f
{
    public static void Main()
    {
        ConsoleKeyInfo tecla;
        int x = 40, y=12;
        int xo1 = 20, yo1 = 15;  // Obstáculo 1
        int xo2 = 25, yo2 = 5;   // Obstáculo 2
        int xo3 = 62, yo3 = 21;  // Obstáculo 3
        float xe1 = 10, ye1 = 10, incr1 = 0.5f;  // Enemigo 1
        int fin = 0;   // 0 = no terminado, 1 = terminado
 
        // Bucle de juego
        while( fin == 0 )
        {
            // Dibujar
            Console.Clear();
            Console.SetCursorPosition(x, y);
            Console.Write("A");
 
            Console.SetCursorPosition(xo1, yo1); // Obstáculos
            Console.Write("o");
 
            Console.SetCursorPosition(xo2, yo2);
            Console.Write("o");
 
            Console.SetCursorPosition(xo3, yo3);
            Console.Write("o");
 
            Console.SetCursorPosition((int) xe1, (int) ye1); // Enemigo
            Console.Write("@");
 
            // 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
            xe1 = xe1 + incr1;
 
            if ((xe1 == 0) || (xe1 == 79))
                incr1 = - incr1;
 
            // Colisiones, perder vidas, etc
            if ( ( (x==xo1) && (y==yo1) )
                || ( (x==xo2) && (y==yo2) )
                || ( (x==xo3) && (y==yo3) )
               )
               fin = 1; 
 
            // Pausa hasta el siguiente "fotograma" del juego
            Thread.Sleep(40);
        }
    }
}
 

Ejercicio propuesto: Afina el juego, para que vaya a 50 fotogramas por segundo, y la velocidad del enemigo sea un 60% de la velocidad del personaje.

Nota: Hay ciertas cosas que no podremos evitar, porque no estamos usando una biblioteca de juegos real, sino la "consola de windows". Por eso, si mantenemos una tecla pulsada, hay un retardo antes de que nuestro personaje se empiece a mover de forma repetitiva, igual que puede ocurrir que dejemos de pulsar la tecla y el personaje se siga moviendo un instante.