How to render at a fixed FPS in a GLFW window? - c++

I am trying to render at 60 FPS but my scene is rendering at a much higher rate than 60 FPS.
This is my code for the Render Loop, is this the correct way to render at a desired FPS or are there better ways?
double lastTime = glfwGetTime(), timer = lastTime;
double deltaTime = 0, nowTime = 0;
int frames = 0, updates = 0;
while (!glfwWindowShouldClose(window))
{
// input
// -----
processInput(window);
// - Measure time
nowTime = glfwGetTime();
deltaTime += (nowTime - lastTime) / limitFPS; // limitFPS = 1.0 / 60.0
lastTime = nowTime;
// - Only update at 60 frames / s
while (deltaTime >= 1.0) {
updates++;
deltaTime--;
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
w.render(); // Render function
frames++;
}
glfwPollEvents();
// - Reset after one second
if (glfwGetTime() - timer > 1.0) {
timer++;
}
glfwSwapBuffers(window);
}

Based on the discussion in comments above, you want to draw a maximum of 60 FPS, but you want the logic to update as often as possible. Correct?
That can be achieved with just one loop, a timer, and an if statement:
const double fpsLimit = 1.0 / 60.0;
double lastUpdateTime = 0; // number of seconds since the last loop
double lastFrameTime = 0; // number of seconds since the last frame
// This while loop repeats as fast as possible
while (!glfwWindowShouldClose(window))
{
double now = glfwGetTime();
double deltaTime = now - lastUpdateTime;
glfwPollEvents();
// update your application logic here,
// using deltaTime if necessary (for physics, tweening, etc.)
// This if-statement only executes once every 60th of a second
if ((now - lastFrameTime) >= fpsLimit)
{
// draw your frame here
glfwSwapBuffers(window);
// only set lastFrameTime when you actually draw something
lastFrameTime = now;
}
// set lastUpdateTime every iteration
lastUpdateTime = now;
}
Everything that you want to execute as often as possible should be in the outer part of that while loop, and everything you want to execute at a maximum of 60 times per second should be inside the if statement.
If the loop takes longer than 1/60th of a second to execute an iteration then your FPS and update rate will drop to whatever rate is achievable for that workload/system.

Related

How would I go about fixing my variable rate SDL timestep?

I my gameloop is going around 10x faster than what it should be and I have no idea how to fix it.
I tried multiple different other variable rate timesteps but none seem to be as effective as this one.
int main(int argc, char* args[])
{
Uint32 t = 0;
Uint32 dt = 10000 / 60.0;
Uint32 currentTime = SDL_GetTicks();
game = new Renderer();
game->init("window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, false);
while(game->running()){
Uint32 newTime = SDL_GetTicks();
Uint32 frameTime = newTime - currentTime;
currentTime = newTime;
while(frameTime > 0.0)
{
float deltaTime = std::min(frameTime, dt);
game->handleEvents();
game->update(deltaTime/1000);
frameTime -= deltaTime;
t += deltaTime;
t += dt;
}
game->render();
}
game->clean();
return 0;
}
Whenever I call
g.transform.position.x+=1/60.0;
in the render function, I expect it to move 1 pixel every 1 second but it moves way to fast.
Does anyone know how I can slow this down or what I'm doing wrong?
It goes too fast because you update your object in the render method.
You have a mix of fixed and variable timestep which will try to catch up if the physics part of your game lags behind, but no restriction on the render method. (which is good)
So you should update your game objects in your update method and then set your object to g.transform.position.x+=deltatime (you probably want another variable in here later, example: g.transform.position.x+=speed*deltatime)
All you should do in game->render() is to draw your object.
This should fix your gameloop timing.
Only reason to render your object at a different position in game->render() would be if you have a fixed timestep in your update method so that you would have to render in between update cycles.
Hope this helps.

Physics in my game gives a wrong result with vsync turned off C++

I calculate Newtonian physics based on gravitation in my 2D game. It works exactly how it's supposed to, when vsync is turned on (60fps), but once I turn it off and gain about 3.5k fps, the character starts to fall incredibly fast. The answer seems obvious, I just need to multiply character's velocity by deltaTime, but I already do that and still no result. It slows down the character a bit, but seems to be sort of not enough..
this is what character's update function looks like:
void Update(float deltaTime) {
if (!onGround) {
acceleration += -Physics::g; // 9.81f
/* EDIT: THIS IS WHAT IT ACTUALLY LOOKS LIKE, sorry*/
SetPosition(position + Vec2(0.0f, 1.0f) * deltaTime * acceleration);
/* instead of this:
SetPosition(position + Vec2(0.0f, 1.0f) * acceleration); */
if (ceiling) {
acceleration = 0;
ceiling = false;
}
} else {
acceleration = 0;
}
}
and here's the calculation of deltaTime
inline static void BeginFrame() {
currentTime = static_cast<float>(glfwGetTime()); // Time in seconds
delta = (currentTime - lastTime);
lastTime = currentTime;
}
What am I missing?
Thanks in advance.
The acceleration means how large the velocity increases per unit time, so you should multiply deltaTime to the acceleration, not only to the velocity.
In other words,
acceleration += -Physics::g; // 9.81f
should be:
acceleration += deltaTime * -Physics::g; // 9.81f

Is my solution to fixed timestep with delta time and interpolation wrong?

I am trying to write simple loop with fixed delta time used for physics and interpolation before rendering the state. I am using Gaffer on games tutorial on fixed timesteps and I tried to understand it and make it work.
float timeStep = 0.01;
float alpha = 1.0;
while (isOpen()) {
processInput();
deltaTime = clock.restart(); // get elapsed time
if (deltaTime > 0.25) { deltaTime = 0.25; } // drop frame guard
accumulator += deltaTime;
while (accumulator >= timeStep) {
// spritePosBefore = sprite.getPosition();
accumulator -= timeStep;
// sprite.move(velocity * timeStep, 0);
// spritePosAfter = sprite.getPosition();
}
if (accumulator > timeStep) { alpha = accumulator / timeStep; } else { alpha = 1.0; }
// sprite.setPosition(Vector2f(spritePosBefore * (1 - alpha) + spritePosAfter * alpha));
clear();
draw(sprite);
display();
}
Now, everything looks good. I have fixed timestep for physics, draw whenever I can after physics are updated and interpolate between two positions. It should work flawless but I can still see sprite stuttering or even going back by one pixel once in a while. Why does it happen? Is there any problem with my code? I spent last two days trying to understand game loop which would ensure me flawless motions but it seems like it doesn't work as I thought it will. Any idea what could be improved?
You should remove the if statement and always calculate alpha; the if statement will never be executed as the condition is always false after the while loop is exited!
After the loop the accumulator will be between 0 and timeStep so you just end up drawing the latest position instead of interpolating.
I don't think the way you do it is necessarily wrong but it looks a bit overcomplicated. I don't understand exactly what you're trying to do so I'm just going to share the way I implement a "fixed time step" in my SFML applications.
The following is the simplest way and will be "good enough" for most applications. It's not the most precise though (the can be a little error between the measured time and the real time) :
sf::Clock clock;
sf::Event event;
while (window_.isOpen()) {
while (window_.pollEvent(event)) {}
if (clock.getElapsedTime().asSeconds() > FLT_FIXED_TIME_STEP) {
clock.restart();
update(FLT_FIXED_TIME_STEP);
}
render();
}
And if you really need precision, you can add a float variable that will act as a "buffer" :
sf::Clock clock;
sf::Event event;
float timeBeforeNextStep = 0.f; // "buffer"
float timeDilation = 1.f; // Useful if you want to slow or speed up time ( <1 for slowmo, >1 for speedup)
while (window_.isOpen()) {
while (window_.pollEvent(event)) {}
timeBeforeNextStep -= clock.restart().asSeconds() * timeDilation;
if (timeBeforeNextStep < FLT_FIXED_TIME_STEP) {
timeBeforeNextStep += FLT_FIXED_TIME_STEP; // '+=', not '=' to make sure we don't lose any time.
update(FLT_FIXED_TIME_STEP);
// Rendering every time you update is not always the best solution, especially if you have a very small time step.
render();
}
}
You might want to use another buffer for rendering (if you want to run at exactly 60 FPS for example).

How can we handle time in SFML/C++?

I am using SFML 2.1 with C++. I want to know that how can we handle our player's movement with a delay for example:
if(right-key-is-pressed)
{
player.move(5, 0);
}
Now we want the player to move to 5 spaces but we want it to take 2 sec to do it.
How can we do it in SFML?
You have to use sf::clock in order to time your game.
http://www.sfml-dev.org/documentation/2.1-fr/classsf_1_1Clock.php
One way to do this is to introduce the concept of frame. Every second can have several frames, say 60. And each frame is a snapshot of objects state at a given time point in that second. You compute the states of objects in the new frame, and then render and show it on the screen at that time point, and continues to compute the frame.
In your example, say I can have 10 frames per second. The speed of the player is 5/2 unit/second. I'll compute the player state, and get player is at 0.25 at 0.1 seconds, 0.5 at 0.2 seconds, 0.75 at 0.3 seconds, and so on.
int main()
{
sf::Clock Clock;
float LastTime = 0;
//Main Game Loop
while(Window.isOpen())
{
/* ... */
float CurTime = Clock.restart().asSeconds();
float FPS = 1.0 / CurTime;
LastTime = CurTime;
/*Then you could multiply the objects move axis speed by FPS*/
Player->Shape.move(Vel.x * FPS, Vel.y * FPS);
Window.clear();
Window.display();
}
return 0
}
Since CurTime = Clock.restart().asSeconds(); you may(more than likely) have to significantly increase the value of your Objects Velocity.

Limit Speed Of Gameplay On Different Computers

I'm creating a 2D game using OpenGL and C++.
I want it so that the game runs at the same speed on different computers, At the moment my game runs faster on my desktop than my laptop (i.e. my player moves faster on my desktop)
I was told about QueryPerformanceCounter() but I don't know how to use this.
how do I use that or is there a better/easier way?
My Display function
void display()
{
static long timestamp = clock();
// First frame will have zero delta, but this is just an example.
float delta = (float)(clock() - timestamp) / CLOCKS_PER_SEC;
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
createBackground();
int curSpeed = (player.getVelocity()/player.getMaxSpeed())*100;
glColor3f(1.0,0.0,0.0);
glRasterPos2i(-screenWidth+20,screenHeight-50);
glPrint("Speed: %i",curSpeed);
glRasterPos2i(screenWidth-200,screenHeight-50);
glPrint("Lives: %i",lives);
glRasterPos2i(screenWidth-800,screenHeight-50);
glPrint("Heading: %f",player.getHeading());
for(int i = 0;i<90;i++){
if (numBullets[i].fireStatus == true){
numBullets[i].updatePosition(player);
if (numBullets[i].getXPos() > screenWidth || numBullets[i].getXPos() < -screenWidth || numBullets[i].getYPos() > screenHeight || numBullets[i].getYPos() < -screenHeight ){
numBullets[i].fireStatus = false;
numBullets[i].reset(player);
numBullets[i].~Bullet();
}
}
}
player.updatePosition(playerTex,delta);
glFlush();
timestamp = clock();
}
My Update positiom method
void Player::updatePosition(GLuint playerTex, float factor){
//draw triangle
glPushMatrix();
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindTexture(GL_TEXTURE_2D, playerTex);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTranslatef(factor*XPos, factor*YPos, 0.0);
glRotatef(heading, 0,0,1);
glColor3f(1.0,0.0,0.0);
glBegin(GL_POLYGON);
glTexCoord2f(0.0, 1.0); glVertex2f(-40,40);
glTexCoord2f(0.0, 0.0); glVertex2f(-40,-40);
glTexCoord2f(1.0, 0.0); glVertex2f(40,-40);
glTexCoord2f(1.0, 1.0); glVertex2f(40,40);
glEnd();
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glPopMatrix();
XPos += speed*cos((90+heading)*(PI/180.0f));
YPos += speed*sin((90+heading)*(PI/180.0f));
}
As a rule, you want to do all gameplay calculations based on a time delta, i.e. the amount of time that has passed since the last frame. This will standardize speed on all machines. Unless you want extreme precision, you can use clock() (from <ctime>) to get the current timestamp.
Example:
void main_loop() {
static long timestamp = clock();
// First frame will have zero delta, but this is just an example.
float delta = (float)(clock() - timestamp) / CLOCKS_PER_SEC;
calculate_physics(delta);
render();
timestamp = clock();
}
void calculate_physics(float delta) {
// Calculate expected displacement per second.
applyDisplacement(displacement * delta);
}
void render() {
// Do rendering.
}
EDIT: If you want higher precision, you should use your OS timer features. On Windows, the most precise method is using QueryPerformanceCounter(). Example
#include <windows.h>
void main_loop(double delta) {
// ...
}
int main() {
LARGE_INTEGER freq, last, current;
double delta;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&last);
while (1) {
QueryPerformanceCounter(&current);
delta = (double)(current.QuadPart - last.QuadPart) / (double)freq.QuadPart;
main_loop(delta);
last = current;
}
}
Most games use a frame time-scaling factor. Essentially, you find the length of the frame your physics and movement are set at and divide it between the actual length of the frame the game is running at (1/fps). This produces a scalar factor which you can multiply by changes in movement to keep all movements consistent while maintaining the benefits from increasing the FPS.
A good example is here.
The best solution to your problem is to only update the positions of your objects once every 10 ms (or something similar) but render the objects as often as possible. This is called "fixed time step" as you only update the game state at fixed intervals. This requires you to decouple the rendering code from the update code (which is a good idea anyway).
Basically (in psudoe code) what you would do is something like:
accumulatedTimeSinceLastUpdate = 0;
while(gameIsRunning)
{
accumulatedTimeSinceLastUpdate += timeSinceLastFrame();
while(accumulatedTimeSinceLastUpdate >= 10) // or another value
{
updatePositions();
accumulatedTimeSinceLastUpdate -= 10;
}
display();
}
This means that if your computer is running super-duper fast display() will be called a lot of times and every now and then updatePositions(). If your computer is ultra slow updatePositions may be called several times for each time display() is called.
Here's another good read (in addition to Mason Blier's):
http://gafferongames.com/game-physics/fix-your-timestep/