3. PRIMER ARRANQUE

Tenéis el proyecto completo en: Tutorial de programación c++ (3/11)

Ya tenemos una estructura más o menos sencilla de seguir. Ahora habrá que mostrar algo en pantalla para comprobar que nuestra Wiz tira bien. Así que vamos a dibujar un mensaje distinto para cada modo de programa. Sencillo, ¿no? Además, aprovecharemos para unificar algunas cosas en un par de funciones.

Lo primero que encontramos en la cabecera es que se ha añadido la siguiente línea:

Código:
#include <SDL/SDL_ttf.h>
Esto significa que vamos a utilizar la librería de texto truetype de SDL, que nos permite utilizar este tipo de fuentes.

Código:
///////////////////////////////////
/*  Variables globales           */
///////////////////////////////////
TTF_Font *font;                 // fuente usada
En las variables globales vemos una nueva. font almacenará una fuente truetype que carguemos del disco para usarla en las funciones de dibujado.

Código:
void draw_text(SDL_Surface* dst, char* string, int x, int y, int fR, int fG, int fB)
{
  if (dst && string && font)
  {
    SDL_Color foregroundColor={fR,fG,fB};
    SDL_Surface *textSurface=TTF_RenderText_Blended(font,string,foregroundColor);
    if (textSurface)
    {
      SDL_Rect textLocation={x,y,0,0};
      SDL_BlitSurface(textSurface,NULL,dst,&textLocation);
      SDL_FreeSurface(textSurface);
    }
  }
}
La función draw_text() dibujará un texto en la pantalla, en la posición x,y y con los colores fR,fG,fB. Primero comprueba que existen los objetos dst (la pantalla u otra superficie), string (la cadena de texto) y font (la fuente).
Si es así, creamos una variable para el color (foregroundColor) y dibujamos el texto en una nueva superficie (textSurface).
Si todo ha ido bien, dibujamos la superficie textSurface sobre la pantalla con la función SDL_BlitSurface() y liberamos la memoria de textSurface.

Código:
void init_game()
{
  joystick=SDL_JoystickOpen(0);
  SDL_ShowCursor(0);

  TTF_Init();
  font=TTF_OpenFont("data/pixantiqua.ttf", 12);
}

void end_game()
{
  // Ponemos la pantalla en negro y salimos
  SDL_FillRect(screen, NULL, 0x000000);
  SDL_Flip(screen);

  if (SDL_JoystickOpened(0))
    SDL_JoystickClose(joystick);
}
También crearemos las funciones init_game() y end_game().
init_game() la llamaremos desde la función main(), y se ocupará de inicializar algunas cosas del juego. Por ahora meteremos la variable joystick, la ocultación del cursor y arrancaremos el sistema truetype con TTF_Init(). Además, cargaremos la fuente pixantiqua.ttf que tenemos en el directorio data.
end_game() se encargará de descargar algunos recursos y liberar la memoria que hayamos ocupado. Por ahora, sólo pondremos la pantalla en negro y liberaremos el joystick.

Código:
void read_menu_keys()
{
  SDL_Event event;
  // Comprueba los eventos de botones
  while (SDL_PollEvent(&event))
  {
    switch (event.type)
    {
    case SDL_JOYBUTTONDOWN:
      switch (event.jbutton.button)
      {
      case GP2X_BUTTON_START:
        done=1;
        break;
      case GP2X_BUTTON_A:
      case GP2X_BUTTON_B:
      case GP2X_BUTTON_X:
      case GP2X_BUTTON_Y:
        program_mode=PROGRAM_MODE_GAME;
        break;
      }
      break;
    }
  }
}
En read_menu_keys() hemos añadido una nueva comprobación. Si pulsamos alguno de los botones A, B, X o Y cambiaremos el modo de programa de MENU a JUEGO con program_mode=PROGRAM_MODE_GAME;

Código:
void draw_menu()
{
  draw_text(screen,"Menu",50,110,255,255,0);
}
En la función que se ocupa de dibujar el modo menú añadiremos una simple línea. Con draw_text() escribiremos el modo en que nos encontramos: Menú, en mitad de la pantalla y de color amarillo.

Código:
void read_game_keys()
{
  SDL_Event event;
  // Comprueba los eventos de botones
  while (SDL_PollEvent(&event))
  {
    switch (event.type)
    {
    case SDL_JOYBUTTONDOWN:
      switch (event.jbutton.button)
      {
      case GP2X_BUTTON_START:
        done=1;
        break;
      case GP2X_BUTTON_A:
      case GP2X_BUTTON_B:
      case GP2X_BUTTON_X:
      case GP2X_BUTTON_Y:
        program_mode=PROGRAM_MODE_PAUSE;
        break;
      }
      break;
    }
  }
}
En read_game_keys() hacemos lo mismo que antes. Si pulsamos cualquiera de los botones pasamos del modo JUEGO al modo PAUSA.

Código:
void draw_game()
{
  draw_text(screen,"Juego",50,110,255,255,0);
}
En draw_game() repetimos la función de dibujar un texto, sólo que en esta ocasión escribiremos Juego, que es el modo en que nos encontramos.

Código:
void read_pause_keys()
{
  SDL_Event event;
  // Comprueba los eventos de botones
  while (SDL_PollEvent(&event))
  {
    switch (event.type)
    {
    case SDL_JOYBUTTONDOWN:
      switch (event.jbutton.button)
      {
      case GP2X_BUTTON_START:
        done=1;
        break;
      case GP2X_BUTTON_A:
      case GP2X_BUTTON_B:
      case GP2X_BUTTON_X:
      case GP2X_BUTTON_Y:
        program_mode=PROGRAM_MODE_MENU;
        break;
      }
      break;
    }
  }
}
En read_pause_keys() volvemos a comprobar los botones y pasamos del modo PAUSA al modo MENU. Así hacemos un recorrido circular por todos los estados.

Código:
void draw_pause()
{
  draw_text(screen,"Pausa",50,110,255,255,0);
}
Finalmente, en draw_pause() dibujamos el texto Pausa, de nuevo el modo en que nos encontramos.

Código:
int main(int argc, char *argv[])
{
  if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO | SDL_INIT_AUDIO)<0)
    return 0;

  screen = SDL_SetVideoMode(320, 240, 16, SDL_SWSURFACE);
  if (screen==NULL)
    return 0;

  init_game();
Como hemos dicho antes, en la función main() añadimos init_game(), para que inicialice algunas cosas del juego.

Código:
  end_game();
Y al salir del bucle principal del programa, lo primero que hacemos es llamar a end_game() y liberar los recursos que hemos ocupado. El resto de la función main() se mantiene exactamente igual a como la dejamos en la lección 2.

Si compiláis el programa y lo ejecutáis, veréis cómo en mirad de la pantalla aparece el texto "Menú". Eso indica que estamos en el modo MENU. Si pulsáis uno de los botones de Wiz, pasaréis secuencialmente por los estados JUEGO y PAUSA. Eso quiere decir que la cosa va bien. Así que... ¿por qué no hacemos un menú en condiciones?