23. Pantalla de ayuda y de créditos

Vamos a ver también cómo añadir más opciones al menú principal. Una de ellas mostrará una pequeña ayuda, que recuerde (por ejemplo) las teclas que se pueden usar durante el juego. Otra será una pantalla de "créditos", que muestre datos sobre el autor de nuestro juego.

Crearemos un par de funciones nuevas. Su estructura será muy similar a la que tenía la presentación, salvo que ahora sólo es necesario esperar hasta que se pulse ESC:

public static void MostrarCreditos()
{
    // ---- Pantalla de presentación --
    Hardware.BorrarPantallaOculta(0, 0, 0);
 
    // Fondo de la presentación
    fondoCreditos.DibujarOculta(0, 0);
 
    // Marcador
    Hardware.EscribirTextoOculta("Creditos",
             250, 200, // Coordenadas
             255, 255, 255, // Colores
            tipoDeLetra);
 
    Hardware.EscribirTextoOculta("Por Nacho Cabanes, 2011",
              250, 300, // Coordenadas
              200, 200, 200, // Colores
             tipoDeLetra);
 
    Hardware.EscribirTextoOculta("ESC- volver",
             650, 530, // Coordenadas
             200, 200, 200, // Colores
            tipoDeLetra);
    Hardware.VisualizarOculta();
 
    do
    {
        Hardware.Pausa(20);
    } while (!Hardware.TeclaPulsada(Hardware.TECLA_ESC));
}
 

Dejamos una "Pausa" dentro del "do..while" para que no use el 100% del procesador para algo tan sencillo como esperar una tecla. Con esa "pausa" ayudamos a mantener la multitarea del sistema operativo.


Ahora tendremos que ampliar la presentación, para que avise de las nuevas opciones, compruebe las teclas necesarias y llame a las nuevas funciones cuando sea el caso:

public static void MostrarPresentacion()
{
    bool finPresentacion = false;
 
    do
    {
        // ---- Pantalla de presentación --
        Hardware.BorrarPantallaOculta(0, 0, 0);
 
        // Fondo de la presentación
        fondoPresentacion.DibujarOculta(0, 0);
 
        // Marcador
        Hardware.EscribirTextoOculta("Jueguecillo",
                 340, 200, // Coordenadas
                 255, 255, 255, // Colores
                 tipoDeLetra);
 
        Hardware.EscribirTextoOculta("Escoja una opción:",
                 310, 300, // Coordenadas
                 200, 200, 200, // Colores
                 tipoDeLetra);
 
        Hardware.EscribirTextoOculta("J.- Jugar una partida",
                 150, 390, // Coordenadas
                 200, 200, 200, // Colores
                tipoDeLetra);
 
        Hardware.EscribirTextoOculta("A.- Ayuda",
                 150, 430, // Coordenadas
                 200, 200, 200, // Colores
                 tipoDeLetra);
 
        Hardware.EscribirTextoOculta("C.- Créditos",
                 150, 470, // Coordenadas
                 200, 200, 200, // Colores
                 tipoDeLetra);
 
        Hardware.EscribirTextoOculta("S.- Salir",
                 150, 510, // Coordenadas
                 200, 200, 200, // Colores
                 tipoDeLetra);
 
        Hardware.VisualizarOculta();
 
        Hardware.Pausa(20);
 
        if (Hardware.TeclaPulsada(Hardware.TECLA_A))
            MostrarAyuda();
 
        if (Hardware.TeclaPulsada(Hardware.TECLA_C))
            MostrarCreditos();
 
        if (Hardware.TeclaPulsada(Hardware.TECLA_J))
            finPresentacion = true;
 
        if (Hardware.TeclaPulsada(Hardware.TECLA_S))
        {
            finPresentacion = true;
            partidaTerminada = true;
            juegoTerminado = true;
        }
    } while (!finPresentacion);
}
 

Esto se haría antes de la parte repetitiva que comprueba pulsaciones de teclas, porque no tiene sentido cargar la imagen múltiples veces:

public static void MostrarPresentacion()
{
    Imagen fondoPresentacion = new Imagen("present.jpg");
    // ---- Pantalla de presentación --
    Hardware.BorrarPantallaOculta(0,0,0);
 
    // Pantalla de fondo
    fondoPresentacion.DibujarOculta(0,0);
 
    // Marcador
    Hardware.EscribirTextoOculta("Jueguecillo",
             340,200, // Coordenadas
             255, 255, 255, // Colores
            tipoDeLetra);
 
    ...
 

El programa completo sería algo como:

// Primer mini-esqueleto de juego en modo gráfico
// Versión "d"
 
using System;
using System.Threading; // Para Thread.Sleep
 
public class Juego05d
{
    struct ElemGrafico
    {
        public int x;
        public int y;
        public int xInicial;
        public int yInicial;
        public int incrX;
        public int incrY;
        public Imagen imagen;
        public bool visible;
    }
 
    static ElemGrafico personaje;
    static Fuente tipoDeLetra;
 
    static int numPremios, numEnemigos, numObstaculos;
 
    static ElemGrafico[] obstaculos;
    static ElemGrafico[] enemigos;
    static ElemGrafico[] premios;
 
    static bool juegoTerminado;
    static int vidas;
    static int puntos;
    static bool partidaTerminada;
    static Random generador;
 
    static Imagen fondoPresentacion;
    static Imagen fondoAyuda;
    static Imagen fondoCreditos;
 
 
    public static void InicializarJuego()
    {
        // Entrar a modo grafico 800x600
        bool pantallaCompleta = false;
        Hardware.Inicializar(800, 600, 24, pantallaCompleta);
 
        // Resto de inicializacion
        tipoDeLetra = new Fuente("FreeSansBold.ttf", 18);
        juegoTerminado = false;
        numPremios = 10;
        numEnemigos = 10;
        numObstaculos = 20;
        obstaculos = new ElemGrafico[numObstaculos];
        enemigos = new ElemGrafico[numEnemigos];
        premios = new ElemGrafico[numPremios];
        generador = new Random();
 
        // Cargo imágenes de elementos
        personaje.imagen = new Imagen("personaje.png");
 
        for (int i = 0; i < numObstaculos; i++)  // Obstaculos
            obstaculos[i].imagen = new Imagen("obstaculo.png");
 
        for (int i = 0; i < numEnemigos; i++)  // Enemigos
            enemigos[i].imagen = new Imagen("enemigo.png");
 
        for (int i = 0; i < numPremios; i++)  // Premios
            premios[i].imagen = new Imagen("premio.png");
 
        // Y cargo las imagenes de la presentación, ayuda y créditos
        fondoPresentacion = new Imagen("present.jpg");
        fondoAyuda = new Imagen("present.jpg");
        fondoCreditos = new Imagen("present.jpg");
    }
 
 
    public static void InicializarPartida()
    {
        // En cada partida, hay que reiniciar ciertas variables
        vidas = 3;
        puntos = 0;
        partidaTerminada = false;
 
        personaje.xInicial = 400;
        personaje.yInicial = 300;
        personaje.x = personaje.xInicial;
        personaje.y = personaje.yInicial;
        personaje.incrX = 10;
        personaje.incrY = 10;
 
        // Genero las posiciones de los elementos al azar
        for (int i = 0; i < numObstaculos; i++)  // Obstaculos
        {
            obstaculos[i].x = generador.Next(50, 700);
            obstaculos[i].y = generador.Next(30, 550);
        }
 
        for (int i = 0; i < numEnemigos; i++)  // Enemigos
        {
            enemigos[i].x = generador.Next(50, 700);
            enemigos[i].y = generador.Next(30, 550);
            enemigos[i].incrX = 5;
        }
 
        for (int i = 0; i < numPremios; i++)  // Premios
        {
            premios[i].x = generador.Next(50, 700);
            premios[i].y = generador.Next(30, 550);
            premios[i].visible = true;
        }
    }
 
 
    public static void MostrarPresentacion()
    {
        bool finPresentacion = false;
 
        do
        {
            // ---- Pantalla de presentación --
            Hardware.BorrarPantallaOculta(0, 0, 0);
 
            // Fondo de la presentación
            fondoPresentacion.DibujarOculta(0, 0);
 
            // Marcador
            Hardware.EscribirTextoOculta("Jueguecillo",
                     340, 200, // Coordenadas
                     255, 255, 255, // Colores
                     tipoDeLetra);
 
            Hardware.EscribirTextoOculta("Escoja una opción:",
                     310, 300, // Coordenadas
                     200, 200, 200, // Colores
                     tipoDeLetra);
 
            Hardware.EscribirTextoOculta("J.- Jugar una partida",
                     150, 390, // Coordenadas
                     200, 200, 200, // Colores
                    tipoDeLetra);
 
            Hardware.EscribirTextoOculta("A.- Ayuda",
                     150, 430, // Coordenadas
                     200, 200, 200, // Colores
                     tipoDeLetra);
 
            Hardware.EscribirTextoOculta("C.- Créditos",
                     150, 470, // Coordenadas
                     200, 200, 200, // Colores
                     tipoDeLetra);
 
            Hardware.EscribirTextoOculta("S.- Salir",
                     150, 510, // Coordenadas
                     200, 200, 200, // Colores
                     tipoDeLetra);
 
            Hardware.VisualizarOculta();
 
            Hardware.Pausa(20);
 
            if (Hardware.TeclaPulsada(Hardware.TECLA_A))
                MostrarAyuda();
 
            if (Hardware.TeclaPulsada(Hardware.TECLA_C))
                MostrarCreditos();
 
            if (Hardware.TeclaPulsada(Hardware.TECLA_J))
                finPresentacion = true;
 
            if (Hardware.TeclaPulsada(Hardware.TECLA_S))
            {
                finPresentacion = true;
                partidaTerminada = true;
                juegoTerminado = true;
            }
        } while (!finPresentacion);
    }
 
 
    public static void MostrarAyuda()
    {
        // ---- Pantalla de presentación --
        Hardware.BorrarPantallaOculta(0, 0, 0);
 
        // Fondo de la presentación
        fondoAyuda.DibujarOculta(0, 0);
 
        // Marcador
        Hardware.EscribirTextoOculta("Ayuda",
                 340, 200, // Coordenadas
                 255, 255, 255, // Colores
                tipoDeLetra);
 
        Hardware.EscribirTextoOculta("(Texto de ejemplo)",
                 310, 300, // Coordenadas
                 200, 200, 200, // Colores
                tipoDeLetra);
 
        Hardware.EscribirTextoOculta("ESC- volver",
                 650, 530, // Coordenadas
                 200, 200, 200, // Colores
                tipoDeLetra);
        Hardware.VisualizarOculta();
 
        do
        {
            Hardware.Pausa(20);
        } while (!Hardware.TeclaPulsada(Hardware.TECLA_ESC));
    }
 
 
    public static void MostrarCreditos()
    {
        // ---- Pantalla de presentación --
        Hardware.BorrarPantallaOculta(0, 0, 0);
 
        // Fondo de la presentación
        fondoCreditos.DibujarOculta(0, 0);
 
        // Marcador
        Hardware.EscribirTextoOculta("Creditos",
                 250, 200, // Coordenadas
                 255, 255, 255, // Colores
                tipoDeLetra);
 
        Hardware.EscribirTextoOculta("Por Nacho Cabanes, 2011",
                  250, 300, // Coordenadas
                  200, 200, 200, // Colores
                 tipoDeLetra);
 
        Hardware.EscribirTextoOculta("ESC- volver",
                 650, 530, // Coordenadas
                 200, 200, 200, // Colores
                tipoDeLetra);
        Hardware.VisualizarOculta();
 
        do
        {
            Hardware.Pausa(20);
        } while (!Hardware.TeclaPulsada(Hardware.TECLA_ESC));
    }
 
 
    public static void Dibujar()
    {
        // -- Dibujar --
        Hardware.BorrarPantallaOculta(0, 0, 0);
 
        // Marcador
        Hardware.EscribirTextoOculta("Vidas        Puntos",
                 0, 0, // Coordenadas
                 255, 255, 255, // Colores
                tipoDeLetra);
 
        Hardware.EscribirTextoOculta(Convert.ToString(vidas),
                 70, 0, // Coordenadas
                 200, 200, 200, // Colores
                tipoDeLetra);
 
        Hardware.EscribirTextoOculta(Convert.ToString(puntos),
                 190, 0, // Coordenadas
                 200, 200, 200, // Colores
                tipoDeLetra);
 
        for (int i = 0; i < numObstaculos; i++)  // Obstáculos
        {
            obstaculos[i].imagen.DibujarOculta(
                (int)obstaculos[i].x, (int)obstaculos[i].y);
        }
 
        for (int i = 0; i < numEnemigos; i++)  // Enemigos
        {
            enemigos[i].imagen.DibujarOculta(
                (int)enemigos[i].x, (int)enemigos[i].y);
        }
 
        for (int i = 0; i < numPremios; i++)  // Premios
        {
            if (premios[i].visible)
            {
                premios[i].imagen.DibujarOculta(
                    premios[i].x, premios[i].y);
            }
        }
 
        personaje.imagen.DibujarOculta(
            personaje.x, personaje.y);
 
        // Finalmente, muestro en pantalla
        Hardware.VisualizarOculta();
    }
 
 
    public static void ComprobarTeclas()
    {
        // -- Leer teclas y calcular nueva posición --
        if (Hardware.TeclaPulsada(Hardware.TECLA_ESC))
            partidaTerminada = true;
 
        if (Hardware.TeclaPulsada(Hardware.TECLA_DER))
            personaje.x += personaje.incrX;
        if (Hardware.TeclaPulsada(Hardware.TECLA_IZQ))
            personaje.x -= personaje.incrX;
        if (Hardware.TeclaPulsada(Hardware.TECLA_ARR))
            personaje.y -= personaje.incrY;
        if (Hardware.TeclaPulsada(Hardware.TECLA_ABA))
            personaje.y += personaje.incrY;
    }
 
 
    public static void MoverElementos()
    {
        // -- 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 <= 50)
                    || ((int)enemigos[i].x >= 700))
                enemigos[i].incrX = -enemigos[i].incrX;
        }
    }
 
 
    public static void ComprobarColisiones()
    {
        // -- 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)
                    partidaTerminada = 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)
                    partidaTerminada = true;
                personaje.x = personaje.xInicial;
                personaje.y = personaje.yInicial;
            }
        }
 
    }
 
 
    public static void PausaFotograma()
    {
        // -- Pausa hasta el siguiente "fotograma" del juego --
        Hardware.Pausa(20);
    }
 
 
    public static void Main()
    {
 
        InicializarJuego();
 
        while (!juegoTerminado)
        {
            InicializarPartida();
            MostrarPresentacion();
 
            // ------ Bucle de juego ------
            while (!partidaTerminada)
            {
                Dibujar();
                ComprobarTeclas();
                MoverElementos();
                ComprobarColisiones();
                PausaFotograma();
            } // Fin del bucle de juego
        }     // Fin de partida
    }         // Fin de Main
}
 

Ejercicio propuesto: Haz que la ayuda muestre textos más detallados: varias frases, que estarán almacenadas en un "array de strings". Deberás recorrer este array usando "for" o "foreach".

(Nota: nuevamente, si quieres ver cómo quedaría el fuente con estos cambios propuestos... tendrás que mirar en el siguiente apartado, que partirá de ese punto).