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

Author Topic: SetFramerateLimit makes the Game stutter  (Read 6071 times)

0 Members and 1 Guest are viewing this topic.

Daepilin

  • Newbie
  • *
  • Posts: 10
    • View Profile
SetFramerateLimit makes the Game stutter
« on: July 28, 2013, 08:12:30 pm »
Hi :)

I've got a little problem with my game. If i use the built in SetFramerateLimit method to limit my Windows Framerate to 60 it varies a bit (not the problem) but has some issues:

1) stuttering. Quite regular the game stutters which results in double or tripple the "normal" rendertime for the window.
2) Framerate is actually below 60. On my system it's on 58, a friend tested it on quite a weak laptop and only got 53Fps(which stayed the same when he underclocked the thing, so i guess it's no lack of performance)

(Fps measured with Fraps, rendertimes with sf::clock. Don't get any Framedrops, when i leave the Limiter out but 1500+FPs is not what i want^^)

i wrote my own functionality, very crude, but working(no drops and bang on 60Fps on my machine), but: i don't really know how to prevent it from using the core it runs on at 100%:

Code: [Select]
void Framework::Render(){

if(mCurrentRenderFrameTime >= 0.01667){
mMainWindow->clear();
mMainStateManager->Render();
mMainWindow->display();

mCurrentRenderFrameTime = 0.0;
}
mCurrentRenderFrameTime += mFrameT / 1000000.0;
}

Code: [Select]
void Framework::RunGame(){
mCurrentRenderFrameTime = 1.0;
while (mMainWindow->isOpen()){

this->HandleEvents();
this->Update();
this->Render();
}
}


Any Tips how i could solve the problem?

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: SetFramerateLimit makes the Game stutter
« Reply #1 on: July 28, 2013, 08:56:43 pm »
It's a know limitation of the system function call from sf::sleep(). The precision can change heavily on different systems. Through that you'll get lower franerates. The stutter might be a cause of it as well, or it might be an issue in combination with your code.

You could use VSync to get a steady frame rate without a busy-wait loop, but there can be some issues as well.

Another option is to use you're own framerate limiter + sf::sleep() and manually adjust the slerp time, to essentially get the wanted FPS.

Can you provide your movement code? At best as a minimal and complete example.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Daepilin

  • Newbie
  • *
  • Posts: 10
    • View Profile
Re: SetFramerateLimit makes the Game stutter
« Reply #2 on: July 28, 2013, 09:05:33 pm »
Well i don't have much movement code to show, as i just have implemented very basic stuff but:

Code: [Select]
void Player::validateMovement(){
//ckeck left corners
mCurrentTilePosition = convertToTilePosition(sf::Vector2i(getCollisionBox().left, getCollisionBox().top));
mFirstNewTilePosition = convertToTilePosition(sf::Vector2i(getCollisionBox().left + getMovementVector().x , getCollisionBox().top/* + getMovementVector().y*/)); //top left
mSecondNewTilePosition = convertToTilePosition(sf::Vector2i(getCollisionBox().left + getMovementVector().x , getCollisionBox().top + getCollisionBox().height/* + getMovementVector().y*/)); //bottom left

//collision
if(mCurrentRoomTiles[mFirstNewTilePosition.x][mFirstNewTilePosition.y].getCollideID() == 1 || mCurrentRoomTiles[mSecondNewTilePosition.x][mSecondNewTilePosition.y].getCollideID() == 1){
setMovementVector(sf::Vector2f(0.0, getMovementVector().y));
}

//doors
else if(mCurrentRoomTiles[mFirstNewTilePosition.x][mFirstNewTilePosition.y].getTileID() == 2 || mCurrentRoomTiles[mSecondNewTilePosition.x][mSecondNewTilePosition.y].getTileID() == 2){
if( (mFirstNewTilePosition.x == 0 && mFirstNewTilePosition.y == 4 ) || (mSecondNewTilePosition.x == 0 && mSecondNewTilePosition.y == 4)) mTeleportTo = "Left";
else if( (mFirstNewTilePosition.x == 7 && mFirstNewTilePosition.y == 0 )) mTeleportTo = "Up";
else if( mSecondNewTilePosition.x == 7 && mSecondNewTilePosition.y == 8) mTeleportTo = "Down";
}


//ckeck top corners
mCurrentTilePosition = convertToTilePosition(sf::Vector2i(getCollisionBox().left, getCollisionBox().top));
mFirstNewTilePosition = convertToTilePosition(sf::Vector2i(getCollisionBox().left /*+ getMovementVector().x*/ , getCollisionBox().top + getMovementVector().y)); //left top
mSecondNewTilePosition = convertToTilePosition(sf::Vector2i(getCollisionBox().left /*+ getMovementVector().x*/ + getCollisionBox().width , getCollisionBox().top + getMovementVector().y)); //right top

//collision
if(mCurrentRoomTiles[mFirstNewTilePosition.x][mFirstNewTilePosition.y].getCollideID() == 1 || mCurrentRoomTiles[mSecondNewTilePosition.x][mSecondNewTilePosition.y].getCollideID() == 1){
setMovementVector(sf::Vector2f(getMovementVector().x, 0.0));
}

//doors
else if(mCurrentRoomTiles[mFirstNewTilePosition.x][mFirstNewTilePosition.y].getTileID() == 2 || mCurrentRoomTiles[mSecondNewTilePosition.x][mSecondNewTilePosition.y].getTileID() == 2){
if( (mFirstNewTilePosition.x == 7 && mFirstNewTilePosition.y == 0 ) || (mSecondNewTilePosition.x == 7 && mSecondNewTilePosition.y == 0)) mTeleportTo = "Up";
else if( (mFirstNewTilePosition.x == 0 && mFirstNewTilePosition.y == 4 )) mTeleportTo = "Left";
else if( (mSecondNewTilePosition.x == 14 && mSecondNewTilePosition.y == 4)) mTeleportTo = "Right";
}


.
        .
        .
}

void MovableObject::moveObject(){
if(mMovementVector.x != 0 || mMovementVector.y != 0){

this->move(mMovementVector.x, mMovementVector.y);

setCollisionBox(sf::FloatRect(mCollisionBox.left + mMovementVector.x, mCollisionBox.top + mMovementVector.y, mCollisionBox.width, mCollisionBox.height));

setCollisionBoxShapePosition(sf::Vector2f(mCollisionBox.left, mCollisionBox.top));
}

}

The first Method is basically a part of my (current) collisiondetection for collisions with the room. It basically sets the movementvector.x and/or .y to 0 if the movement would cause a collision. (not the optimal way, in future i want to adjust it depending on the distance to the collisionobject to move right up to it)

The second method moves the playersprite, collisionbox and my visualization (ofc just for development).

the movementvector is set via 8 else if comparisons:

Code: [Select]
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left)){
setMovementVector(sf::Vector2f(-getMovementSpeed(), 0.0f));
setNextAnimation(3);
}
(getMovementspeed()  just returns a double value)

the code is not yet made to work without the inbuild frame limiter and will let the player cross the whole room in 1sec without it, but that is a fixable problem.

but i get those framedrops in the menu as well (without much to draw) even though i don't know if it stutters there.
(the stutter, to describe it better) is a really short break in a continous movement(with pressed key)

i actually had someone else test it (quite a powerfull i5 as cpu and 8gigs of ram, quite a bit stronger than my machine). He "felt" no stuttering but had the same framedrops. But i guess he just did not notice as my cpu is below 10% with the built in limiter, which makes me think cpu performance is not an issue.

« Last Edit: July 28, 2013, 09:14:01 pm by Daepilin »

Daepilin

  • Newbie
  • *
  • Posts: 10
    • View Profile
Re: SetFramerateLimit makes the Game stutter
« Reply #3 on: July 29, 2013, 04:24:50 pm »
Okay, i actually got my own frame limiter running with individual timesteps for update and render methods.

But: I guess there is now way to increase sf:sleep accuracy? Atm i loose about 3-6 fps on my machine, though i guess that number will differ.

or is my Code just broken:

Code: [Select]
while(mMainWindow->isOpen()){

HandleEvents();
Update();

if(mCurrentRenderTime >= mRenderT){
Render();
mCurrentRenderTime = 0.0;
}

mCurrentFrameTime = mMainClock->restart().asMicroseconds();
mCurrentRenderTime += mCurrentFrameTime;

mSleepTime = sf::microseconds(mUpdateT - mCurrentFrameTime);
sf::sleep(mSleepTime);
}

mUpdateT is 1667 and mRenderT is 16667.  I sure know that sf::sleep is not that accurate, but maybe i have some additional errors in there^^

zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
Re: SetFramerateLimit makes the Game stutter
« Reply #4 on: July 29, 2013, 05:27:13 pm »
You really should not be concerned over 3-6 FPS. The FPS will always vary across multiple computers (even on the same computer). This is why you should implement FPS independent update code. The easiest way to do this is to use a fixed time step and then accumulate delta time in a variable until it is time to update.

                mSleepTime = sf::microseconds(mUpdateT - mCurrentFrameTime);
                sf::sleep(mSleepTime);

You should take into consideration here that some computers will not be able to run your loop in under the time set in mUpdateT. That would mean you should check for a negative number before calling sf::Sleep()
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: SetFramerateLimit makes the Game stutter
« Reply #5 on: July 29, 2013, 05:32:41 pm »
Sleeping with negative time is ok, it doesn't do anything at all.
Back to C++ gamedev with SFML in May 2023

Daepilin

  • Newbie
  • *
  • Posts: 10
    • View Profile
Re: SetFramerateLimit makes the Game stutter
« Reply #6 on: July 29, 2013, 05:42:11 pm »
I thought so.

And honestly: my CPU is not that modern anymore (phenom II x4 955), this runs in one thread and even in a frame where rendering is done it's not even close to drop a frame ( without every limit i easily get 1500fps+, handle events and updates both not even take 100microS most of the time)

A guy in a different forum testet it on a 1.2Ghz dual core notebook and it gave him stable fps^^ so at least now it's no issue.

But yeah, my update methods themselves are given the Frametime and will base all time relevant calculations on it, so there should be no problem when some frames drop on very very low end machines.

And i think i will include an option to set the FPS target, for those 120Hz monitor guys^^ (+ maybe a benchmark for really low end computers)

But thanks to you both :)
« Last Edit: July 29, 2013, 05:45:13 pm by Daepilin »

zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
Re: SetFramerateLimit makes the Game stutter
« Reply #7 on: July 29, 2013, 08:26:24 pm »
Sleeping with negative time is ok, it doesn't do anything at all.

Actually if you read windows documentation this isn't true.

Windows defines -1 as infinite so if you sleep with -1 you will never regain control of your thread. Also anything less than -1 will throw an error(at least in the .NET framework implementation of thread sleep).

C++ Sleep()
.NET Thread.Sleep()
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Back to C++ gamedev with SFML in May 2023

zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
Re: SetFramerateLimit makes the Game stutter
« Reply #9 on: July 29, 2013, 08:35:17 pm »
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: SetFramerateLimit makes the Game stutter
« Reply #10 on: July 29, 2013, 11:27:50 pm »
Sleeping with negative time is ok, it doesn't do anything at all.
In SFML, this is an implementation detail and not a documented feature. Relying on it is a bad idea.

The current implementation only hides logic errors, there is no meaningful scenario where one would pass a negative time to sf::sleep(). Laurent should rather write
assert(duration >= sf::Time::Zero);
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

TideSofDarK

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: SetFramerateLimit makes the Game stutter
« Reply #11 on: July 30, 2013, 12:04:38 pm »
Have same problem, the most bad thing is sf::View scrolling. It stutters as hell!

TideSofDarK

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: SetFramerateLimit makes the Game stutter
« Reply #12 on: July 30, 2013, 12:55:33 pm »
Also when i enable VSync its fine, but loads CPU on 100%
« Last Edit: July 30, 2013, 01:14:59 pm by TideSofDarK »