Can I use a traditional "game loop" with Cinder instead of the default draw() and update() functions?

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

2 Likes

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
}
3 Likes

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. :slight_smile:

3 Likes