I want to be able to make a small physics engine and will need access to the FPS and to be able to change it. From my experience, I feel like I would need it this way, unless there is a work-around.
Why don’t you run your physics in a secondary thread? You don’t want to render your physics faster than vsync (likely 60fps) anyway so running cinder’s loop unbounded is just wasteful. gl::enableVerticalSync(false)
and settings->setFrameRate(10000);
will do it, though.
If you insist on using the main thread, have a look at how the update
and draw
calls are implemented in the App
classes and just reimplement what you need, but this seems like a code smell to me.
Hi,
I’d suggest to simply disableFrameRate()
in your setup and then go for the excellent method described by Glenn Fiedler in his Fix Your Timestep article.
~Paul
Thanks for the article(s). They are very informative! I should have found these sooner.
I am having some trouble implementing this. I looked at the App and AppMsw and didn’t find any useful information. Are there any examples I should take a look at?
Hi,
here’s some code to get you up to speed:
class YourApp : public App {
public:
void setup() override;
void update() override;
void draw() override;
void simulate( double elapsed );
double mSlowMotion = 1.0;
bool mIsPaused = false;
bool mFixedTimeStep = true;
};
void YourApp::setup()
{
// This will disable the frame rate limiter of Cinder.
disableFrameRate();
// This will disable vertical sync, causing tearing but allowing the fastest frame rate.
gl::enableVerticalSync( false );
}
void YourApp::update()
{
// Use a fixed time step for a steady 60 updates per second.
static const double timestep = 1.0 / 60.0;
static double time = getElapsedSeconds();
static double accumulator = 0.0;
// Calculate elapsed time since last frame.
const double elapsed = getElapsedSeconds() - time;
time += elapsed;
// Simulate your physics using a fixed time step.
if( mFixedTimeStep ) {
accumulator = glm::min( accumulator + elapsed, 0.1 );
while( accumulator >= timestep ) {
simulate( mIsPaused ? 0.0 : timestep * mSlowMotion );
accumulator -= timestep;
}
}
else {
accumulator = 0.0;
simulate( mIsPaused ? 0.0 : elapsed * mSlowMotion );
}
}
void simulate( double elapsed )
{
// do your physics in here, 'elapsed' is the time since the previous simulation step in seconds
}
void YourApp::draw()
{
// draw your graphics here
}
After working with @paul.houx on a project a while back and using his fixed timestep setup, I created a class that does this, which I’ve since used in just about every project I’ve worked on:
Supports a couple nice things like pausing, seeking time, and disabling fixed timestep. Use it like this:
// in class declaration:
ma::WorldClock mWorldClock;
void YourApp::setup()
{
mWorldClock.getSignalClockStep().connect( signals::slot( this, &YourApp::updateScene ) );
}
void YourApp::update()
{
mWorldClock.update( ci::app::getElapsedSeconds() );
}
void YourApp::updateScene()
{
if( mScene ) {
mScene->update();
}
}
Thanks Paul.