I'm making a game using SFML Library, I wanna implement a function showing the seconds on the screen since the running of the program, and it will get increasing until the window is closed. I tried this:
sf::Clock clock;
while (window.isOpen())
{
sf::Time elapsed = clock.restart();
updateGame(elapsed);
}
But I have no idea how it's work or even if it's the right function.
Here is my code so far https://github.com/basmaashouur/GamesLib/blob/master/cards/main.cpp
There are multiple ways to get the number of seconds.
First of all, you can use an exclusive sf::Clock for this that's never reset:
sf::Clock clock;
const unsigned int seconds = static_cast<unsigned int>(clock.getElapsedTime().asSeconds());
As an alternative, you can use an sf::Time to accumulate the time between frames (e.g. inside your updateGame() function):
sf::Clock clock;
sf::Time time;
time += clock.restart();
const unsigned int seconds = static_cast<unsigned int>(time.asSeconds());
Related
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.
Can I make a loop using sf::time class, as when I try and do this my program crashes.
while(time.asSeconds() <= 10.0f)
This is the while loop I used with sf::Time class.
EDIT:
sf::Clock clock; // Initializing clock starts counting time.
while(someCondition)
{
sf::Time time = clock.getElapsedTime();
//It's going to execute do something() until time is higher than 10.0f
while(time.asSeconds() <= 10.0f)
{
//we need this to ensure that we won't fall into the infinite loop
time = clock.getElapsedTime();
do something()
//Optional: clock.restart(); If you want your code to be executed every x seconds.
}
}
First you have to create sf::Clock variable, then grab time from clock to sf::Time variable.
This code move a sprite across the screen relative to time. However it appears to jump to the left every couple of seconds.
int ogreMaxCell = 9;
if (SpriteVector[i].getPosition().x > ogreDirectionX[i] )
{
sf::Vector2f ogreDirection = sf::Vector2f(-1,0);
float ogreSpeed = 1;
sf::Vector2f ogreVelocity = ogreDirection * ogreSpeed * 250000.0f * dt.asSeconds();
this->SpriteVector[i].move(ogreVelocity);
//gets the spritesheet row
orcSource.y = getCellYOrc(orcLeft);
}
if (ogreClock.getElapsedTime().asMilliseconds() > 250)
{
orcxcell = (orcxcell + 1) % ogreMaxCell;
ogreClock.restart();
}
SpriteVector[i].setTextureRect(sf::IntRect(orcSource.x + (orcxcell * 80), orcSource.y, 80, 80));
The statement for time is:
sf::Time dt; // delta time
sf::Time elapsedTime;
sf::Clock clock;
elapsedTime += dt;
dt = clock.restart();
Any insight as to why this is happening?
Regards
You didn't show how you implemented your time function, 2 possibilities:
The first possibility is where you, you declared the time variables outside of
the time function's loop, in that case the result is movement with some varying degree, but it looks to me from the if structure the error most likely lies in possibility 2. 250000.0f is an insainly huge number to have to use when dealing with offsets, and the use of ogre.clock tells me #2 is more likely
2
Both the variables and the declarations of the time function are looped.
I threw that function in a compilier, and set cout to output both values as microseconds.
output is elapsedTime is always 0, and dt is always around 0-4ish microseconds, except every so often for a certian reason it is equal 400-2000ish microseconds.
The effect of this is that it made you have to use a second clock to control your time so your animations didn't glitch, and your animation will jump to the left every so often, because dt goes from being 4 microseconds to 1500 microseconds randomly. It also explains why you have to multiply by such a huge constant, because you are using miliseconds,, and keep getting infintesmily small values for dt.
There are a few problems in the time function
dt = clock.restart(); =/= 0
you will always get some small time value because in the time it takes to reset the clock to 0 and to give the clock's value to the sf::time variable.
When the animation jumps it's because in that particular cycle it took the computer a little longer to assign the value after the clock reset.
the fix is pretty simple:
declare the variables outside the loop structure,
and adjust the code like this:
//declare before loop, if you dont, elapsed time constantly gets set to 0
sf::Time dt; // delta time
sf::Time elapsedTime;
sf::Clock clock;
//startloop structure of your choice
elapsedTime += clock.getElapsedTime();
dt = clock.getElapsedTime();
clock.restart();
and modify the second if statement to
if (elapsedTime.asMilliseconds() > 250)
{
orcxcell = (orcxcell + 1) % ogreMaxCell;
elapsedTime = milliseconds(0)
}
sf::Time is just a variable, the clock has to do the counting.
Hope this helps.
p.s. always write declarations outside of your loop structures, it works okay most of the time, but from time to time it will cause you to get strange errors like this one, or random crashes.
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 at the moment trying to Programm my first Game in SFML (and my first overall) but i ran into the Problem that i get a stutter about once a second. During such a stutter the Frametime is 3 to 4 times higher than normal which is really noticeable as long i don't run really high FPS (300+).
No Problem (at least atm) as performance is not an Issue, but:
When doing that my movement Method really freaks out and moves way way slower that it's supposed to do.
my Movement method:
void Player::Update(float frametime){
mMovementSpeedTimefactor = frametime * 60 / 1000.0f;
setMovementVector(sf::Vector2f( mMovementVector.x * mMovementSpeedTimefactor, mMovementVector.y *mMovementSpeedTimefactor));
validateMovement();
//std::cout << mTestClock->restart().asMilliseconds() << std::endl;
moveObject();
this->updateAnimation();
}
frametime is the frametime in Milliseconds, and i Multiply by 60, as my movementspeed is set as a value for pixel/second and not per frame.
movementspeed is 5, so the character should move 5 px per second, whatever FPS( and therefore Frametime) i have.
But: that gives me really jumpy movement, as those "stutterframes" result in a jump, and on nto stuttering frames the palyer moves a lot slower than it should.
my mainloop is really simple, just
while(mMainWindow->isOpen()){
HandleEvents();
Update();
Render();
}
while using the inbuild framelimiter (tried writing my own, but i get the very same result, as long as i use sf:sleep to regulate FPS for not having the cpu core running at 100% load) to 300 FPS.
So yeah, i could just set my standard speed to 1 instead of 5, but
setframeratelimit is not very accurate, so i get some variation in movementspeed, that i really not like.
anyone has an idea, what i could best do? Maybe i'm not seeing the forest for all the trees ( i actually have no idea if you say that in english :P) but as this is my first game i have no experience to look back upon.
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();
}
EDIT: If this is not really what you want, see "Fix your timestep!" which Laurent Gomila himself linked in the SFML forum.
When frametime is really high or really low your calculations may not work correctly because of float precision issues. I suggest setting standard speed to, maybe, 500 and mMovementSpeedTimeFactor to frametime * 60 / 10.0f and check if the issue still happens.