So the movement in my game isn't smooth. It looks like every tenth of a second the game freezes for a very short period of time then continues along until it freezes again.
You can see here as the rectangle moves, it stops for a short while then continues along.
(http://i.imgur.com/Ng5mUaE.gif)
Here is my code for updating and rendering the game:
float dt = 1.0 / 60.0f;
float accumulator = 0.0f;
while (window.isOpen())
{
float frameTime = clock.restart().asSeconds();
accumulator += frameTime;
while(accumulator >= dt)
{
pollEvents();
updateStates(dt);
clearInput();
accumulator -= dt;
}
window.clear();
drawStates(window);
window.display();
}
Is my code flawed in someway and is this behavior a result of it? Or should this create smooth movement and thus the problem is with something else?
I should better use window.setFramerateLimit
I've experimented with this function before and if it set it to the match the frame rate I've implemented in my code it has no visual impact which would make since because it just checks to see if an amount of time has passed before displaying the contents.
I've decided to experiment a little more with it though. Here's what I changed the code to:
window.setFramerateLimit(60);
while (window.isOpen())
{
pollEvents();
updateStates(dt);
clearInput();
window.clear();
drawStates(window);
window.display();
}
So after making this change I noticed that the movement is the same, it's not smooth. This tells me that the code I wrote in the first post is probably fine and that the issue is elsewhere. I figured maybe it's my computer so I ran the application on a different less powerful computer and strangely the movement is smooth! Now that I think about it this issue started happening when I applied the windows 10 anniversary update to my computer. The graphics drivers are up to date so I have absolutely no clue why this would be happening. Does anyone have any ideas?
Fixed Timestep creates a reliable and regular update for physics and logic. It doesn't, however, fix the refresh rate of the window. This is decided by the OS; if it would prefer to do something else, your window will have to wait.
Therefore, each frame shown isn't guaranteed to be perfectly regular and, in some cases, not at the exact time you expect a frame - it could be part way.
Frame interpolation can help solve this visual artifact. It's the very last part in the Fix Your Timestep article. I commented about this here recently and there is a small accompanying video to that comment showing the difference. See the comment here (http://en.sfml-dev.org/forums/index.php?topic=20655.msg148416#msg148416) (also includes a link to Fix Your Timestep article).
I looked at your video and it appears the same issue is happening with me so I implemented interpolation but unfortunately the issue is still there. Here is a minimal code example which is also on github (https://github.com/CasualKyle/TimestepTesting):
main.cpp
#include "State.h"
int main()
{
sf::RenderWindow window(sf::VideoMode(1500, 1000), "Timestep Testing");
window.setKeyRepeatEnabled(false);
State state;
sf::Clock clock;
float dt = 1.0f / 60.0f;
float accumulator = 0.0f;
while(window.isOpen())
{
sf::Event event;
while(window.pollEvent(event))
if(event.type == sf::Event::Closed)
window.close();
accumulator += clock.restart().asSeconds();
while(accumulator >= dt)
{
state.update(dt);
accumulator -= dt;
}
float interp = accumulator / dt;
window.clear();
state.draw(window, interp);
window.display();
}
return 0;
}
State.h
#pragma once
#include "SFML\Window.hpp"
#include "SFML\Graphics.hpp"
class State
{
public:
State();
void update(float timeStep);
void draw(sf::RenderWindow& window, float interp);
private:
sf::RectangleShape rect;
sf::Font font;
sf::Text fps;
sf::Text dps;
sf::Clock clockUpdate;
sf::Clock clockDraw;
int frames;
int draws;
sf::Vector2f pos;
sf::Vector2f lastPos;
};
State.cpp
#include "State.h"
State::State() : rect(sf::Vector2f(100.0f, 100.0f))
{
font.loadFromFile("lucon.ttf");
fps.setFont(font);
dps.setFont(font);
fps.setPosition(10.0f, 0.0f);
dps.setPosition(10.0f, 30.0f);
frames = -1;
draws = -1;
}
void State::update(float timeStep)
{
if(clockUpdate.getElapsedTime().asSeconds() >= 1.0f) {
fps.setString("FPS: " + std::to_string(frames));
frames = 0;
clockUpdate.restart();
}
frames++;
sf::Vector2f d;
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Key::W))
d.y = -1;
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Key::S))
d.y = 1;
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Key::A))
d.x = -1;
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Key::D))
d.x = 1;
lastPos = pos;
pos += 150.0f * d * timeStep;
rect.setPosition(pos);
}
void State::draw(sf::RenderWindow& window, float interp)
{
if(clockDraw.getElapsedTime().asSeconds() >= 1.0f) {
dps.setString("Draw Calls: " + std::to_string(draws));
draws = 0;
clockDraw.restart();
}
draws++;
window.draw(fps);
window.draw(dps);
sf::Vector2f posInterp = pos * interp + lastPos * (1.0f - interp);
rect.setPosition(posInterp);
window.draw(rect);
}
I'm getting a solid 60 frames per second and around 800 draw calls per second but the movement is still noticeably jittery. I also noticed that if I comment out the following code from main.cpp the issue goes away and the movement is buttery smooth.
sf::Event event;
while(window.pollEvent(event))
if(event.type == sf::Event::Closed)
window.close();
It appears that calling window.pollEvent() is causing the movement to be jittery.
I'm getting a solid 60 frames per second and around 800 draw calls per second
How? If you are drawing 60 frames per second and drawing three things per frame, you should be getting 180 draw calls per second.
Sorry, I meant that the state.draw() function is getting called about 800 times per second. This doesn't seem irregular to me because since state.draw() is inside the while(window.isOpen()) loop it's going to get lots and lots of calls basically as fast as the CPU can do it.
When I run the minimal application on a different less powerful I get again a solid 60 frames per second and about 400 calls to state.draw() per second which would make since seeing that it's got a Pentium processor and my main computer has a core i7. (I know the CPU isn't everything and if you want the full specs of each computer I can give them to you.) And the movement is smooth. So I don't know I feel like the issue isn't with the code.
Okay so here is how I can get the movement to be smooth:
- Run it on a different computer
Looks smooth to me when I compile it. Maybe a Driver, or a GPU global settings issue?
This also helps the case.
- Take out this code:
sf::Event event;
while(window.pollEvent(event))
if(event.type == sf::Event::Closed)
window.close();
- Restart my computer. Yes, when I restart my computer the movement is smooth but at the end of the day when it's time for me to work on the project the jitteryness comes back. So I restart my computer and everything is fine but the next day after I get home from work and decide to do some development at the end of the day I have to again restart it.
I said this before but this only started happening after I applied the Window 10 anniversary update to my computer which was August 1st if I remember correctly. I've ran the Intel Driver Update Utility (http://www.intel.com/content/www/us/en/support/detect.html?iid=dc_iduu) and it does not return back that the graphics drivers are not up to date.
There was no need to change the timestep in that example to 1/30 from 1/5; you can toggle between 1/5 and 1/60 by pressing Space. The resulting timestep information text in the title bar is showing 1/60 because it's expecting either 1/5 or 1/60 so chooses one. tl:dr; Use the example as is and press Space :P
Just so you know, the 1/5 is there to show just how much interpolation does. Running at 1/5 with interpolation switched on has motion that is as smooth as 1/60 with interpolation on. ;)
Oh okay I didn't notice the code that changed the time step to 1/60 when the space bar is pressed and yeah, using interpolation while the time step is 1/5 sure does show you how beneficial interpolation can be.
I may be seeing things but it looks like "Time passed" is stuttering when the circle does. This would suggest that the window itself is being delayed.
I guess the most important (you might think it's too obvious) but required unasked questioned is:
Is this on a release build or does it only occur during debug builds?
It does look a little like the "Time passed" is stuttering when the circle does in the gif. But when it's running on my computer the "Time passed" doesn't stutter. I think it just didn't record the application as well as it runs. And as for the question of if there's a difference with it running on a release vs a debug build. No there is not, I get the same stuttery movement regardless of if it's a release or debug build.
Could be valuable information: Like with my application commenting out this code in your example makes the issue go away:
sf::Event event;
while(window.pollEvent(event))
{
...
}
Try timing the frames and outputting that information to see if there any unusual spikes.
Like with my application commenting out this code in your example makes the issue go away:
sf::Event event;
while(window.pollEvent(event))
{
// ...
}
You shouldn't remove this. It's very important that a window deals with its events. Every application must do this; if it doesn't, the operating system is likely to consider the application as unresponsive/crashed and may close it.
Plus, how else would you close the window? ;D
If the positions are interpolated to make smooth movements that means that i must use non integer values for moving views. ¿That will cause problems? ¿What i should do?
I was using this function to store the decimals and only setting positions with integer values.
void Movement::moveNowInteger(sf::Vector2f n)
{
if(n.x > 0.f) process_move_right += n.x;
if (n.x < 0.f) process_move_left += (-n.x);
if (n.y > 0.f) process_move_down += n.y;
if (n.y < 0.f) process_move_up += (-n.y);
if (process_move_right > 1.f)
{
moveNow(sf::Vector2f(std::floor(process_move_right), 0.f));
process_move_right -= std::floor(process_move_right);
}
else if (process_move_left > 1.f)
{
moveNow(sf::Vector2f(-std::floor(process_move_left), 0.f));
process_move_left -= std::floor(process_move_left);
}
if (process_move_down > 1.f)
{
moveNow(sf::Vector2f(0.f, std::floor(process_move_down)));
process_move_down -= std::floor(process_move_down) ;
}
if (process_move_up > 1.f)
{
moveNow(sf::Vector2f(0.f, -std::floor(process_move_up)));
process_move_up -= std::floor(process_move_up);
}
}
Currently i'm integrating your kairos library to my game and i can move the view with a smooth movement and without flickering. The problem comes when i keep the program 1 minute or more moving the camera, it begins stuttering exaggeratedly.
The problem was in the transitions between scenerios, i move the camera like in megaman and then run a lua script to load enemies that causes fps go from 60 to 55 generating the graphics corruption with the time.
Is this file access?
Does this camera move still stutter without this loading?
The problem has been solved and has nothing to do with scripts, just was a collateral effect. The problem was that i was updating everything in this loop
while (timestep.isTimeToIntegrate())
{
..
update(dt);
..
}
Now i'm updating with your library in my MovementComponent class and in the Camera class and i quit this checking in the gameloop. I need to read more about time controlling and understand better your library.