1
General / I'm losing my mind implementing a fixed frame rate.
« on: February 03, 2024, 05:17:53 pm »
Hi all,
This problem has existed in my game across two laptops for months now but I've decided to tackle it. Over the past week I've tried to understand how to smooth the movement in my game as currently stutters are very prominent.
I've been browsing videos, tutorials. I've seen both the Fix Your Timestep! and DeWitters pages detailing how to make it independent of frame rate and interpolate for smoothness.
I have an example below with a circle and trying to start as simple as possible.
Before this example I had two positions for the circle, one would be the actual position, the other would be interpolated based on this position and an alpha - calculated by the proportion of the timestep (accumulated_time / time_per_frame). In both scenarios, the issue I'm having is that, after profiling the time for events, updates and rendering, rendering time varied considerably. From what I can see, the frameTime varying - making the alpha for interpolation not consistent, could be the issue?
I looked into the differences with setting a framerate limit on the window and vsync, the former made the rendering time consistent, but it didn't affect the result.
I'm really struggling in just getting to a point of smooth movement and any direction is much appreciated, if you want any details in terms of hardware set up, if you'd guide me on how best to do this - I can.
Thank you!
This problem has existed in my game across two laptops for months now but I've decided to tackle it. Over the past week I've tried to understand how to smooth the movement in my game as currently stutters are very prominent.
I've been browsing videos, tutorials. I've seen both the Fix Your Timestep! and DeWitters pages detailing how to make it independent of frame rate and interpolate for smoothness.
I have an example below with a circle and trying to start as simple as possible.
#include <iostream>
#include <SFML/Graphics.hpp>
#include <fstream>
int main() {
sf::RenderWindow window(sf::VideoMode(1920, 1080), "SFML Test");
// window.setFramerateLimit(0);
// window.setFramerateLimit(60);
// window.setVerticalSyncEnabled(false);
float speed = 1.0f;
sf::Vector2f direction = sf::Vector2f(1.0f, 0);
sf::CircleShape circle;
circle.setRadius(20.0f);
circle.setOrigin(circle.getRadius(), circle.getRadius());
circle.setPosition(0, window.getSize().y/2);
sf::Time TIME_PER_FRAME = sf::seconds( 1.0f / 60.0f );
sf::Clock clock;
sf::Time accumulator;
sf::Time frameTime;
sf::Clock profileClock;
sf::Time eventsTime;
std::vector<sf::Time> eventsTimes;
sf::Time updateTime;
std::vector<sf::Time> updateTimes;
sf::Time renderTime;
std::vector<sf::Time> renderTimes;
while(window.isOpen()) {
frameTime = clock.restart();
accumulator += frameTime;
// events
sf::Event event;
while(window.pollEvent(event)) {
if (event.key.code == sf::Keyboard::Escape) {
if (event.type == sf::Event::KeyPressed) {
window.close();
}
}
}
eventsTimes.push_back(profileClock.restart());
// update
while (accumulator >= TIME_PER_FRAME) {
circle.move(direction*speed);
accumulator -= TIME_PER_FRAME;
}
//interpolate
circle.move(direction*speed*(accumulator/TIME_PER_FRAME));
updateTimes.push_back(profileClock.restart());
//render
window.clear();
window.draw(circle);
window.display();
renderTimes.push_back(profileClock.restart());
}
std::ofstream myfile;
myfile.open ("time_logs.csv");
for (sf::Time i : eventsTimes) {
myfile << i.asMicroseconds() << ",";
}
myfile << std::endl;
for (sf::Time i : updateTimes) {
myfile << i.asMicroseconds() << ",";
}
myfile << std::endl;
for (sf::Time i : renderTimes) {
myfile << i.asMicroseconds() << ",";
}
myfile.close();
return EXIT_SUCCESS;
}
#include <SFML/Graphics.hpp>
#include <fstream>
int main() {
sf::RenderWindow window(sf::VideoMode(1920, 1080), "SFML Test");
// window.setFramerateLimit(0);
// window.setFramerateLimit(60);
// window.setVerticalSyncEnabled(false);
float speed = 1.0f;
sf::Vector2f direction = sf::Vector2f(1.0f, 0);
sf::CircleShape circle;
circle.setRadius(20.0f);
circle.setOrigin(circle.getRadius(), circle.getRadius());
circle.setPosition(0, window.getSize().y/2);
sf::Time TIME_PER_FRAME = sf::seconds( 1.0f / 60.0f );
sf::Clock clock;
sf::Time accumulator;
sf::Time frameTime;
sf::Clock profileClock;
sf::Time eventsTime;
std::vector<sf::Time> eventsTimes;
sf::Time updateTime;
std::vector<sf::Time> updateTimes;
sf::Time renderTime;
std::vector<sf::Time> renderTimes;
while(window.isOpen()) {
frameTime = clock.restart();
accumulator += frameTime;
// events
sf::Event event;
while(window.pollEvent(event)) {
if (event.key.code == sf::Keyboard::Escape) {
if (event.type == sf::Event::KeyPressed) {
window.close();
}
}
}
eventsTimes.push_back(profileClock.restart());
// update
while (accumulator >= TIME_PER_FRAME) {
circle.move(direction*speed);
accumulator -= TIME_PER_FRAME;
}
//interpolate
circle.move(direction*speed*(accumulator/TIME_PER_FRAME));
updateTimes.push_back(profileClock.restart());
//render
window.clear();
window.draw(circle);
window.display();
renderTimes.push_back(profileClock.restart());
}
std::ofstream myfile;
myfile.open ("time_logs.csv");
for (sf::Time i : eventsTimes) {
myfile << i.asMicroseconds() << ",";
}
myfile << std::endl;
for (sf::Time i : updateTimes) {
myfile << i.asMicroseconds() << ",";
}
myfile << std::endl;
for (sf::Time i : renderTimes) {
myfile << i.asMicroseconds() << ",";
}
myfile.close();
return EXIT_SUCCESS;
}
Before this example I had two positions for the circle, one would be the actual position, the other would be interpolated based on this position and an alpha - calculated by the proportion of the timestep (accumulated_time / time_per_frame). In both scenarios, the issue I'm having is that, after profiling the time for events, updates and rendering, rendering time varied considerably. From what I can see, the frameTime varying - making the alpha for interpolation not consistent, could be the issue?
I looked into the differences with setting a framerate limit on the window and vsync, the former made the rendering time consistent, but it didn't affect the result.
I'm really struggling in just getting to a point of smooth movement and any direction is much appreciated, if you want any details in terms of hardware set up, if you'd guide me on how best to do this - I can.
Thank you!