Como manter o FPS constante

Postado por Yoshio Iwamoto em 26/05/2007

Para quem está programando joguinhos simples em C/C++ usando a API do Windows vou dar (no bom sentido) uma dica sobre como manter o FPS constante e intenso (no bom sentido).

Sem um controle seu jogo irá processar os gráficos na velocidade do processador. Os computadores tem velocidades diferentes e as aplicações não tem um processamento constante e igual, seu jogo poderá rodar a 124 FPS, mas se mexer o mouse irá para 81 FPS, por exemplo.

Antes de continuar você tem que conhecer o básico de como criar uma janela usando a Win32 API. Terá que usar também o PeekMessage ao invés do GetMessage no loop que pega os eventos (mensagens).

PeekMessage: não aguarda por mensagens se a fila de mensagens (Message Queue) estiver vazia.


Agora vamos a lógica da coisa, você tem que "pausar" esse loop em determinados intervalos, por exemplo, se quiser 60 FPS terá que pausar 60 vezes por segundo de modo que no final a soma dos intervalos atinja 1 segundo. Para pausar use o Sleep, porém ele trabalha em milisegundos, mas é só dividir 1000.0 (milisegundos) por 60.0 (FPS).

Sleep: faz a thread suspender por um período de tempo (em milisegundos).


  1. Sleep(16.66);
  2. // ou
  3. Sleep(1000.0/60.0);


Pronto! Rápido e prático que nem miojo. :D

Agora se for um jogo pesado você terá que levar em contar o tempo de cada execução do loop. Use a função GetTickCount para capturar o tempo.

GetTickCount: retornar o tempo em milisegundos (DWORD) desde que o sistema foi iniciado (zera quando atinge 49,7 dias ou quando tem um eclipse solar).


A cada loop some 16.66 ao tempo de execução do loop anterior, subtraia pelo tempo atual e o resultado será o tempo que o loop deve aguardar (Sleep). Se o resultado for negativo então o loop não deve aguardar.

Código abaixo pode ser mais esclarecedor:

  1. // ...
  2. int iSleepTime = 0;
  3. BOOL bPeekMsgRes;
  4. DWORD lastTime = GetTickCount();
  5.  
  6. while(1) // Main event loop
  7. {
  8.  
  9. bPeekMsgRes = PeekMessage(&Msg,
  10. NULL,
  11. 0,
  12. 0,
  13. PM_REMOVE);
  14. if(bPeekMsgRes)
  15. {
  16. if(Msg.message == WM_QUIT)
  17. {
  18. break; // Break main event loop
  19. } else {
  20. TranslateMessage(&Msg);
  21. DispatchMessage(&Msg);
  22. }
  23. }
  24.  
  25. /* ---- Main game processing ---- */
  26. // Corta, pica e fatia no jogo...
  27.  
  28. /* ---- FPS control ---- */
  29. lastTime += 16.66;
  30.  
  31. iSleepTime = lastTime - GetTickCount();
  32.  
  33. if(iSleepTime > -1)
  34. {
  35. // Normal
  36. Sleep(iSleepTime);
  37. } else {
  38. // Lento
  39. printf("OMG! Tá lento isso hein?\n");
  40. }
  41. }
  42.  
  43. /* ---- Game Over ---- */
  44. // ...


obs: Tem um "printf" ali que só vai aparecer se a janela tiver um prompt. Você pode compilar sua aplicação/jogo/miojo para que seja exibido o prompt junto, não sei como se faz isso no VisualC++, mas no DevC++ (GCC) crie um projeto "Win32 Console" ou compile com "-mconsole".

Trackback URI | RSS dos comentários

Deixe um comentário

Av. Conselheiro Nébias, 368A, Cj. 413
Vila Mathias - Santos - SP
Telefone: (13) 3345-4580

© 2008 - 2009 Stiod. Todos os direitos reservados.