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.
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.
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.