Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Time management won't work  (Read 1918 times)

0 Members and 1 Guest are viewing this topic.

CTryn

  • Newbie
  • *
  • Posts: 5
    • View Profile
Time management won't work
« on: April 09, 2012, 08:37:23 am »
Hello,

for the last few hours I've been trying to resolve a problem regarding the time management in my
SFML2 program. I want to make sure my program runs with the same speed on different computers.

I know there have been plenty of threads about this in the past but the problem is those either
use a function which is not available anymore (getframetime) or they don't go too much into
detail to clarify this matter for me.

Code: [Select]
#include <SFML/Audio.hpp>
#include <SFML/Graphics.hpp>

int main()
{
sf::VideoMode VMode(800, 600, 32);
sf::RenderWindow Window(VMode, "Empty Window");

sf::CircleShape circle;
circle.setRadius(8);
circle.setOutlineColor(sf::Color(0, 100, 100));
circle.setOutlineThickness(3);
circle.setPosition(10, 20);
circle.setFillColor(sf::Color(0, 255, 255));

sf::Clock clock;
clock.restart();

int updateNext = clock.getElapsedTime().asMilliseconds();

int cx, cy;
cx = 10;
cy = 20;

while (Window.isOpen())
{
sf::Event Event;
while (Window.pollEvent(Event))
{
switch (Event.type)
{
case sf::Event::Closed:
Window.close();
break;
default:
break;
}
}

Window.draw(circle);
Window.display();

Window.clear(sf::Color(0, 0, 0));

while (clock.getElapsedTime().asMilliseconds() > updateNext)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
circle.setPosition(cx-=2, cy);
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
circle.setPosition(cx+=2, cy);

}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
circle.setPosition(cx, cy-=1);
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
circle.setPosition(cx, cy+=1);
}
updateNext += 1/60;
}
}

return EXIT_SUCCESS;
}

I never really understood how these timing functions work.
I know you save the elapsed time since the program started but what time exactly is measured
by the start of each loop?
Code: [Select]
while (clock.getElapsedTime().asMilliseconds() > updateNext)
Shouldn't it be the time until the start of this loop (which would increase after every loop)?
I also don't quite get why this should help limiting the speed at which the loop is executed by
comparing it to the time since the program has started. And why do you add 1/60 to the elapsed
time since the program has started? I do know this is the desired framerate as 1/60 is equal to '60hz'
though.
Then again, the above code doesn't work anyway, so I'm not sure if my above assumptions are correct.

How do I make it work and how exactly does it work?

Thanks in advance,
CTryn

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: Time management won't work
« Reply #1 on: April 09, 2012, 11:42:27 am »
I'm not sure what exactly you're trying to achive but the provided code looks kind of odd.
I guess you want the time between a frame and then calculate the FPS value.

If you define the frametime as the time it takes to update all the logic and draw your drawables, you can do this very easy. Create a sf::Clock and restart it either at the beginning or at the end of the whole game loop. Since you want to work with this time difference you need to save the value from the clock before restarting it.
sf::Clock clock;
sf::Time deltaT;
while(window.isOpen())
{
   // Put the rest of the game loop either here
   deltaT = clock.restart(); // Note .restart() also returns the elapsed time
   // or here
}

For the calculation of the FPS value you have to decide how precise you want to have it. First of all you need to understand that you always deal with the passed FPS value. Second since FPS equals frames per second you have to decide what resolution you want for the seconds. If you choose to get the FPS value every single frame, you'd just have to divide 1.f/deltaT.asSeconds(). It's not really recommended since there can be random spikes for a single frame, so you probably want more the average FPS value.
For that you have to count how many frames get drawn and messure the time up to a specific value. Since one second is a pretty big number you can also just take a fraction of it like 0.5 seconds.

if(clock.getElapsedTime().asSeconds() >= 0.5) // 0.5 seconds
{
      fps = 2*frames; // frames/0.5 = frames*2
      frames = 0;
      clock.restart();
}
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

CTryn

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Time management won't work
« Reply #2 on: April 09, 2012, 12:01:50 pm »
Hello,

thanks for your reply - but this is not what I'm trying to achieve. Sorry for expressing myself not
clearly enough.

I want my program to run on every computer with the same speed regardless of the hardware being
used, which is actually kind of a basic move but I somehow am not able to do it. Not timing it would
make this program run way too fast on my computer.
There's an article on the SFML homepage on how to do it with SFML 1.6:
http://www.sfml-dev.org/tutorials/1.3/window-time.php

But this won't work with SFML2 of course.

Thanks in advance,
CTryn

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: Time management won't work
« Reply #3 on: April 09, 2012, 12:16:34 pm »
This is quite easy then. Just calculate the speed for your movements with the deltaT seen above.
sf::Vector2f pos = sprite.getPosition();
pos.x = pos.x+speed*deltaT;
sprite.setPosition(pos);
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

CTryn

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Time management won't work
« Reply #4 on: April 09, 2012, 12:39:26 pm »
Alright, thanks for your help!