int main()
{
RenderWindow window(VideoMode(1280,720), "Game");
window.setActive(false);
std::thread gameThread(game, &window);
while (window.isOpen())
{
Event event;
while (window.pollEvent(event))
{
if (event.type == Event::Closed)
window.close();
}
}
gameThread.join();
return 0;
}
I'm making a basic game loop, and I noticed that every second or so the frametime will spike, sometimes up to 50 ms for a frame or two. I realized that when I comment out while (window.pollEvent(event)), the stuttering stops. Could this be a bug with SFML, or am I just doing something wrong?
Platform - Windows 10
Compiler - MSVC 2015
SFML version - 2.4.0
I got the frametime measurements by writing
Time elapsedTime = clock.getElapsedTime();
Int64 frameTime = elapsedTime.asMicroseconds() - oldTime.asMicroseconds();
fps.setString(std::to_string(frameTime));
oldTime = elapsedTime;
into the loop
EDIT - Now the issue persists no matter whether the event loop is commented out or not. Which is strange, because that definitely wasn't the case yesterday.
Related
Several months ago I made a Fourier Transform program using SFML 2.0. I used anti-aliasing level 8 and it looked perfectly fine. Just recently however (not quite sure when the problem began since I have not touched it in a while), it seems to have broken.
Whenever I draw a line it looks dotted and whenever something moves, it flashes between two states and it doesn't completely clear after calling window.clear(). It's not just that program however. Anytime I use any level of anti-aliasing greater than 0, even in SFML 2.5.1, the same problem occurs.
Here is the some sample code which does not work as it should on my computer:
#include <SFML/Graphics.hpp>
int main()
{
sf::Vertex line[2] =
{
sf::Vertex(sf::Vector2f(0, 0)),
sf::Vertex(sf::Vector2f(800, 0))
};
sf::ContextSettings settings;
settings.antialiasingLevel = 8.0;
sf::RenderWindow window(sf::VideoMode(800, 600), "Test", sf::Style::Close, settings);
window.setVerticalSyncEnabled(true);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
line[1].position.y += 1.0;
window.clear();
window.draw(line, 2, sf::Lines);
window.display();
}
return 0;
}
When the line finishes sweeping, it looks
like this
As this used to not be a problem, I don't think it's SFML's fault. I am using Windows 10 and my computer uses an integrated Intel UHD Graphics 620 graphics card, both of which have not changed since before the problem started happening. On a side note, I have not noticed any other programs on my computer break, only the ones I made.
I've been working on this little framework for my game today and realized that moving delays when moving around. I've used SFML before and have had the same problem, but never bothered to fix it. I'm wondering if anyone has had a similar issue and has found a solution.
Here's an example of the code which is giving me the slight pause in movement:
int main(){
sf::RenderWindow window (sf::VideoMode(640, 480), "Window");
//window.setVerticalSyncEnabled(true);
sf::Texture tex;
tex.loadFromFile("Assets/Textures/player.png");
sf::Sprite s;
s.setTexture(tex);
while (window.isOpen()){
sf::Event event;
while (window.pollEvent(event)){
if (event.type == sf::Event::Closed)
window.close();
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)){
s.move(0.01f, 0.0f);
}
window.clear();
window.draw(s);
window.display();
}
}
The delay/pause/whatever I'm experience is very slight but I can notice it and it's really bugging me. Just seeing the slight break in movement when none of the values alter makes my programming mind extremely sad.
The keyboard input will have a delay just like if you hold a key in Microsoft Word. To get around this, you could create a variable and set it to true when a key is pressed.
int main(){
sf::RenderWindow window (sf::VideoMode(640, 480), "Window");
//window.setVerticalSyncEnabled(true);
sf::Texture tex;
tex.loadFromFile("Assets/Textures/player.png");
sf::Sprite s;
s.setTexture(tex);
bool moving = false;
while (window.isOpen()){
sf::Event event;
while (window.pollEvent(event)){
if (event.type == sf::Event::Closed)
window.close();
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)){
moving = true;
}
if (moving) {
s.move(0.01f, 0.0f);
}
window.clear();
window.draw(s);
window.display();
}
}
This sounds like a framerate/timing issue. One frame in a 60hz game is 16.666.. milliseconds, but on Windows at least, the system clock only has a resolution of 1ms, so your delays are going to be either 16ms or 17ms. This inaccuracy results in occasional jitter as some frames are skipped (or rendered twice, in your case, giving the appearance of a short pause) even if vsync is enabled.
If you can get manual control of frame timing, e.g. by disabling sf::RenderWindow's framerate limit and calling sf::sleep directly, one solution is to delay each frame in the sequence: 17, 17, 16, 17, 17, 16, so that the long-term average is closer to 60hz, minimizing jitter.
I have never used SFML so I can't provide any code but I hope this points you in the right direction.
You should also ensure that your monitor's refresh rate is the same as your game's framerate. SFML might already be doing this automatically.
I am using SFML 2.1 in Code Blocks and I can't figure out how to use Vectors to make clones of my asteroid sprite. It keeps saying that asteroid_V hasn't been declared, and a warning box pops up saying it is "using characters that are illegal in the selected coding" and that they "were changed to protect [me] from losing data".
The objective of this program is to continuously create asteroid sprites that will spawn at random points above the screen before dropping straight down. There were other sprites and aspects in the program but I removed them from this post to properly condense it. This appears to be the only problem after all.
int n;
int main()
{
RenderWindow window;
window.setFramerateLimit(30);
RenderWindow mainMenu;
srand( time(0));
Texture asteroid_Pic;
asteroid_Pic.loadFromFile("Asteroid.png");
std::vector<sf::Sprite> asteroid(n, Sprite(asteroid_Pic));
for (int i = 0; i < asteroid.size(); i++){
asteroid[n].setOrigin(15, 15);
asteroid[n].getPosition();
asteroid[n].setPosition(x = rand() % 790 + 10, y = rand() % -10 - 50);
}
// run the program as long as the window is open
while (window.isOpen())
{
// check all the window's events that were triggered since the last iteration of the loop
Event event;
while (window.pollEvent(event))
{
// "close requested" event: we close the window
if (event.type == Event::Closed){
window.close();
}
asteroid[n].setPosition(x, y+=1);
asteroid[n].rotate(1);
// clear the window with black color
window.clear(Color::Black);
// draw everything here...
// window.draw(...);
window.draw(player1);
window.draw(asteroid[n]);
// end the current frame
window.display();
}
return 0;
}
You have another while (window.isOpen()) inside your main loop. Your program will enter the main loop and then never get out of that inner loop. It will never get to drawing at least once.
You need to get rid of the inner while (window.isOpen()) loop and find another way.
Although the original question was about timers, you can find a basic explanation of a game loop here. You have to handle time in you loop if you want to do something (move sprites, create new ingame entities) based on time.
I'm currently working on a platformer and trying to implement a timestep, but for framerate limits greater than 60 the CPU usage goes up from 1% to 25% and more.
I made this minimal program to demonstrate the issue. There are two comments (lines 10-13, lines 26-30) in the code that describe the problem and what I have tested.
Note that the FPS stuff is not relevant to the problem (I think).
I tried to keep the code short and simple:
#include <memory>
#include <sstream>
#include <iomanip>
#include <SFML\Graphics.hpp>
int main() {
// Window
std::shared_ptr<sf::RenderWindow> window;
window = std::make_shared<sf::RenderWindow>(sf::VideoMode(640, 480, 32), "Test", sf::Style::Close);
/*
When I use the setFramerateLimit() function below, the CPU usage is only 1% instead of 25%+
(And only if I set the limit to 60 or less. For example 120 increases CPU usage to 25%+ again.)
*/
//window->setFramerateLimit(60);
// FPS text
sf::Font font;
font.loadFromFile("font.ttf");
sf::Text fpsText("", font, 30);
fpsText.setColor(sf::Color(0, 0, 0));
// FPS
float fps;
sf::Clock fpsTimer;
sf::Time fpsElapsedTime;
/*
When I set framerateLimit to 60 (or anything less than 60)
instead of 120, CPU usage goes down to 1%.
When the limit is greater, in this case 120, CPU usage is 25%+
*/
unsigned int framerateLimit = 120;
sf::Time fpsStep = sf::milliseconds(1000 / framerateLimit);
sf::Time fpsSleep;
fpsTimer.restart();
while (window->isOpen()) {
// Update timer
fpsElapsedTime = fpsTimer.restart();
fps = 1000.0f / fpsElapsedTime.asMilliseconds();
// Update FPS text
std::stringstream ss;
ss << "FPS: " << std::fixed << std::setprecision(0) << fps;
fpsText.setString(ss.str());
// Get events
sf::Event evt;
while (window->pollEvent(evt)) {
switch (evt.type) {
case sf::Event::Closed:
window->close();
break;
default:
break;
}
}
// Draw
window->clear(sf::Color(255, 255, 255));
window->draw(fpsText);
window->display();
// Sleep
fpsSleep = fpsStep - fpsTimer.getElapsedTime();
if (fpsSleep.asMilliseconds() > 0) {
sf::sleep(fpsSleep);
}
}
return 0;
}
I don't want to use SFML's setFramerateLimit(), but my own implementation with the sleep because I will use the fps data to update my physics and stuff.
Is there a logic error in my code? I fail to see it, given it works with a framerate limit of for example 60 (or less). Is it because I have a 60 Hz monitor?
PS: Using SFML's window->setVerticalSync() doesn't change the results
I answered another similar question with this answer.
The thing is, it's not exactly helping you with CPU usage, but I tried your code and it is working fine under 1% cpu usage at 120 FPS (and much more). When you make a game or an interactive media with a "game-loop", you don't want to lose performance by sleeping, you want to use as much cpu time as the computer can give you. Instead of sleeping, you can process other data, like loading stuff, pathfinding algorithm, etc., or just don't put limits on rendering.
I provide some useful links and code, here it is:
Similar question: Movement Without Framerate Limit C++ SFML.
What you really need is fixed time step. Take a look at the SFML Game
development book source code. Here's the interesting snippet from
Application.cpp:
const sf::Time Game::TimePerFrame = sf::seconds(1.f/60.f);
// ...
sf::Clock clock;
sf::Time timeSinceLastUpdate = sf::Time::Zero;
while (mWindow.isOpen())
{
sf::Time elapsedTime = clock.restart();
timeSinceLastUpdate += elapsedTime;
while (timeSinceLastUpdate > TimePerFrame)
{
timeSinceLastUpdate -= TimePerFrame;
processEvents();
update(TimePerFrame);
}
updateStatistics(elapsedTime);
render();
}
If this is not really what you want, see "Fix your timestep!"
which Laurent Gomila himself linked in the SFML forum.
I suggest to use the setFrameRate limit, because it's natively implemented in SFML and will work a lot better.
For getting the elapsed time you must do :
fpsElapsedTime = fpsTimer.getElapsedTime();
If I had to implement something similar, I would do:
/* in the main loop */
fpsElapsedTime = fpsTimer.getElapsedTime();
if(fpsElapsedTime.asMillisecond() >= (1000/framerateLimit))
{
fpsTimer.restart();
// All your content
}
Other thing, use sf::Color::White or sf::Color::Black instead of (sf::Color(255,255,255))
Hope this help :)
I'm making my first game in allegro 5, it's a snake game. In order to move the snake game I'd want to use a squared grid which I made, so the snake moves at regular intervals.
How can I use timers to make an event happen at a certain amount of time?
For example, I want my snake to move every second in the direction set, I know how to control him but I don't know how to create an event which happens at a certain interval. I'm using Codeblocks IDE with Windows XP SP3
Most people who create games with Allegro used a fixed interval timing system. This means X times per second (often 60 or 100), you process input and run a logic cycle. Then, if you have time left over, you draw a frame of graphics.
To create a timer that ticks at 60 FPS and register it with an event queue:
ALLEGRO_TIMER *timer = al_create_timer(1 / 60.0);
ALLEGRO_EVENT_QUEUE *queue = al_create_event_queue();
al_register_event_source(queue, al_get_timer_event_source(timer));
Now somewhere in your main event loop:
al_start_timer(timer);
while (playingGame)
{
bool draw_gfx = false;
do
{
ALLEGRO_EVENT event;
al_wait_for_event(queue, &event);
if (event.type == ALLEGRO_EVENT_TIMER)
{
do_logic();
draw_gfx = true;
}
else if (event.type == ... )
{
// process keyboard input, mouse input, whatever
// this could change the direction the snake is facing
}
}
while (!al_is_event_queue_empty(queue));
if (draw_gfx)
{
do_gfx();
draw_gfx = false;
}
}
So now in do_logic(), you can move your snake one unit in the direction it is facing. This means it would move 60 units per second. You can use fractional units if you need more granularity.
You may want to take a look at some of the demos that come with Allegro, as they have full featured event loops. It's too much to include as a single SO answer.