Hi There!
I´m redesigning my
game loop. Yes, I have read these two famous articles:
Fix Your Timestep!deWiTTERS Game LoopI wrote a simple
main.cpp file to test this methods. This is my
deWitters implementation:
// Timestep (Constant Game Speed independent of Variable FPS)
sf::Clock miReloj;
const int TICKS_POR_SEGUNDO = 25;
const int SALTEO_TICKS = 1000 / TICKS_POR_SEGUNDO;
const int MAX_SALTEO_FRAMES = 5;
int loops;
float interpolacion;
sf::Int32 proximo_tick = miReloj.getElapsedTime().asMilliseconds();
// This method doesnt look good with VSync On (jerkiness)
window.setVerticalSyncEnabled (false);
// Start the game loop
while (window.isOpen()) {
// Clear screen
window.clear();
// Update (the events are handled in the actualizar function)
loops = 0;
while (miReloj.getElapsedTime().asMilliseconds() > proximo_tick && loops < MAX_SALTEO_FRAMES) {
actualizar (window); // It doesnt use delta time here
proximo_tick += SALTEO_TICKS;
++loops;
}
interpolacion = static_cast <float> (miReloj.getElapsedTime().asMilliseconds() + SALTEO_TICKS - proximo_tick) / static_cast <float> (SALTEO_TICKS);
// Draw
dibujar (window, interpolacion);
// Update the window
window.display();
}
return EXIT_SUCCESS;
This are my
update/drawing functions using
deWitters method:
void actualizar (sf::RenderWindow &rw) {
// Process events
sf::Event event;
while (rw.pollEvent (event)) {
... // imagine this code :)
} // end while
// Update game objects
if (!seMueve) return;
if ((posRenderCirc.x > 700.0f) || (posRenderCirc.x < 20.0f)) {
velCirculo = -velCirculo;
}
posRenderCirc.x += velCirculo; // Just add velocity, no dt here
}
void dibujar (sf::RenderTarget &rt, const float dt) {
// Copy original position
sf::Vector2f posInterpolada (posRenderCirc);
// If it´s moving, calculate the interpolated position
if (seMueve) {
posInterpolada.x += velCirculo * dt; // velCirculo is a float (the object speed)
}
circulo.setPosition (posInterpolada); // Draw object at interpolated position
rt.draw (circulo);
}
This works fine (with VSync off). But I want to allow the user to select if he/she wants to activate or not the vertical synchronization. Ok, this is my
GafferonGames method implementation:
// Timestep (Fix Your Timestep!)
sf::Clock miReloj;
const float dt = 1.0f / 30.0f;
float tiempoActual = miReloj.getElapsedTime().asSeconds();
float acumulador = 0.0f;
// VSync friendly
window.setVerticalSyncEnabled (false);
// Start the game loop
while (window.isOpen()) {
// Clear screen
window.clear();
// Update
float tiempoNuevo = miReloj.getElapsedTime().asSeconds();
float tiempoFrame = tiempoNuevo - tiempoActual;
if (tiempoFrame > 0.25f) {
tiempoFrame = 0.25f; // Avoid "Spiral of death"
}
tiempoActual = tiempoNuevo;
acumulador += tiempoFrame;
// Run update in dt sized chunks
while (acumulador >= dt) {
actualizar (window, dt); // using delta time
acumulador -= dt;
}
const float interpolacion = acumulador / dt;
// Draw with interpolation
dibujar (window, interpolacion);
// Update the window
window.display();
}
return EXIT_SUCCESS;
The
GafferonGames method update/drawing functions:
void actualizar (sf::RenderWindow &rw, const float tiempoDelta) {
// Process events
sf::Event event;
while (rw.pollEvent (event)) {
... // super sexy code here
} // end while
// Update game objects
if (!seMueve) return;
if ((posRenderCirc.x > 700.0f) || (posRenderCirc.x < 20.0f)) {
velCirculo = -velCirculo;
}
posRenderCirc.x += velCirculo * tiempoDelta;
}
void dibujar (sf::RenderTarget &rt, const float alphaInterp) {
sf::Vector2f posInterpolada (posRenderCirc);
if (seMueve) {
posInterpolada.x += alphaInterp;
}
circulo.setPosition (posInterpolada);
rt.draw (circulo);
}
This is working good, with VSync on or off. My game
update function is running at fixed 30 FPS and the
drawing is running at 60 (VSync on)/3500 fps.
So... is the
GafferonGames method
THE way to go?
Is there any
better/optimized/sexy way to do this?
What method are you guys using?