Tutorial de SDL – Parte 22 – Gerenciamento do tempo

Continuando nossa série de artigo traduzidos do site lazyfoo, agora veremos como lidar com a passagem de tempo em nosso aplicativo.

Uma parte importante de qualquer tipo de API de jogos é a habilidade de gerenciar o tempo. Nesse artigo, iremos criar um timer que podemos reiniciar.
//Using SDL, SDL_image, SDL_ttf, standard IO, strings, and string streams
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#include <stdio.h>
#include <string>
#include <sstream>
Nesse artigo, estaremos usando streams de strings e por isso iremos incluir o cabeçalho sstream que é vem por padrão junto com seu compilador C++.
bool loadMedia()
{
   //Loading success flag
   bool success = true;
   //Open the font
   gFont = TTF_OpenFont( "22_timing/lazy.ttf", 28 );
   if( gFont == NULL )
   {
      printf( "Failed to load lazy font! SDL_ttf Error: %s\n", TTF_GetError() );
      success = false;
   }
   else
   {
      //Set text color as black
      SDL_Color textColor = { 0, 0, 0, 255 };
      //Load prompt texture
      if( !gPromptTextTexture.loadFromRenderedText( "Press Enter to Reset Start Time.", textColor ) )
      {
         printf( "Unable to render prompt texture!\n" );
         success = false;
      }
   }
   return success;
}
Como mencionado no artigo sobre a renderização de fontes, você deve minimizar a quantidade de vezes que você renderiza texto. Teremos uma textura para mostrar um texto e uma textura para exibir o tempo em milissegundos. A textura do tempo muda a cada quadro, de forma que temos que renderiza-la a cada quadro, mas a textura do texto não muda, assim podemos renderiza-la uma única vez na função de carregamento do arquivo.
//Main loop flag
bool quit = false;
//Event handler
SDL_Event e;
//Set text color as black
SDL_Color textColor = { 0, 0, 0, 255 };
//Current time start time
Uint32 startTime = 0;
//In memory text stream
std::stringstream timeText;
Antes de entrarmos no loop principal, precisamos declarar algumas variáveis.As duas que precisamos atentar são startTime (do tipo Unsigned integer de 32 bits) e a timeText que é um stream de string.
Para aqueles de vocês que nunca usaram um stream de string, apenas saiba que elas trabalham de forma análoga a iostream mas ao invés de escrever ou ler do terminal, elas permitem escrever ou ler de uma string na memória. Isso será mais fácil de visualizar quando estivermos usando-as no programa.
//While application is running
while( !quit )
{
   //Handle events on queue
   while( SDL_PollEvent( &e ) != 0 )
   {
      //User requests quit
      if( e.type == SDL_QUIT )
      {
         quit = true;
      }
      //Reset start time on return keypress
      else if( e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_RETURN )
      {
         startTime = SDL_GetTicks();
      }
   }
Existe uma função chamada SDL_GetTicks que retorna o tempo em milissegundos desde o momento que o programa foi iniciado. Nesse exemplo, teremos um timer que será reiniciado a cada vez que pressionamos a tecla Enter.
Lembre como inicializamos o tempo inicial com 0 no início do programa? ISso significa que o tempo do timer é o tempo atual desde que o programa foi iniciado retornado por SDL_GetTicks. Se formos reiniciar o timer quando SDL_GetTicks estiver em 5000 milissegundos (5 segundos), então o tempo atual será 10000 milissegundos – o tempo inicial seria 10000 menos 5000. Assim, mesmo que o timer contido por SDL_GetTicks não tenha sido reiniciado, podemos manter um registro dos tempos iniciais relativos e resetar esse inicio.
//Set text to be rendered
timeText.str( "" );
timeText << "Milliseconds since start time " << SDL_GetTicks() - startTime;
Agora usaremos nosso stream de string. Primeiro chamamos str com uma string vazia para inicializar o stream como vazio. Em seguida, tratamos ela como cout e imprimimos “Milissegundos desde o início” e o tempo atual menos o tempo inicial relativo, de forma que seja impresso o tempo desde a última vez que iniciamos o timer.
//Render text
if( !gTimeTextTexture.loadFromRenderedText( timeText.str().c_str(), textColor ) )
{
   printf( "Unable to render time texture!\n" );
}
Agora que temos o tempo em um stream de string, podemos obter uma string a partir dele e usa-la para renderizar o tempo atual com uma textura.
//Clear screen
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF ); SDL_RenderClear( gRenderer );
//Render textures gPromptTextTexture.render( ( SCREEN_WIDTH - gPromptTextTexture.getWidth() ) / 2, 0 );
gTimeTextTexture.render( ( SCREEN_WIDTH - gPromptTextTexture.getWidth() ) / 2, ( SCREEN_HEIGHT - gPromptTextTexture.getHeight() ) / 2 );
//Update screen
SDL_RenderPresent( gRenderer );
Finalmente, renderizamos o texto e o tempo na tela.
Baixe os arquivo de código do exemplo desse artigo aqui.