Note: as per Arturo’s correction in post below i made a one line mod to the code to use a more accurate frame timing
Hi Folks, as i was just wandering through a piece of code tidying up i starting to take out my framerate dependencies (of course this should be done as the code is being built!). Most folks here maybe know this, but some won’t Whenever you play a console game the coders have always taken out framerate dependencies to accomplish a standard rate of movement for objects. In a racing game we want our car in our racing game to drive at 110km/h irrespective of framerate.
For those who are new to this but just want some code, here is a quick little Hare and Tortoise codelet, that just needs dropping into an OF emptyExample…
#include "testApp.h"
float framerateMult;
//--------------------------------------------------------------
void testApp::setup(){
framerateMult = 1.0f;
ofSetFrameRate(60);
}
//--------------------------------------------------------------
void testApp::update(){
framerateMult = 60.0f/(1.0f/ofGetLastFrameTime()); // changed as per Arturo correction..thanks
if(ofGetElapsedTimef()< 10.0f) ofSetFrameRate(120);
else if(ofGetElapsedTimef()< 20.0f) ofSetFrameRate(60);
else if(ofGetElapsedTimef()< 30.0f) ofSetFrameRate(30);
else if(ofGetElapsedTimef()< 40.0f) ofSetFrameRate(10);
}
//--------------------------------------------------------------
void testApp::draw(){
int startLine = 30;
static float harePos = 0.0f;
static float tortoisePos = 0.0f;
float blightersSpeed = 0.3f;
string info = "fps: " + ofToString(ofGetFrameRate(),2)
+ "\nframerateMult: " + ofToString(framerateMult,2) ;
ofDrawBitmapString(info, 10, ofGetHeight()-40);
//Draw the timeline
int littleStep = 10;
int bigStep = 100;
ofSetColor(255, 255, 255, 255);
for(int x = startLine; x<ofGetWidth()-100; x+=littleStep)
{
if(x%bigStep == 0)
ofRect(x,ofGetHeight()/2-20, 2, 80);
else
ofRect(x,ofGetHeight()/2, 1, 40);
}
//Move the hare
harePos += blightersSpeed;
//Draw the hare
ofSetColor(128, 0, 0, 255);
ofRect(startLine+harePos,ofGetHeight()/2-40, 20, 20);
info = "hare\nSpeed " + ofToString(blightersSpeed * ofGetFrameRate(), 2) + " km/h";
ofDrawBitmapString(info, startLine+harePos,ofGetHeight()/2-70);
//Move the tortoise
tortoisePos += blightersSpeed*framerateMult;
//Draw the tortoise
ofSetColor(0, 0, 128, 255);
ofRect(startLine+tortoisePos,ofGetHeight()/2+60, 20, 20);
info = "tortoise\nSpeed " + ofToString(blightersSpeed*framerateMult * ofGetFrameRate(), 2) + " km/h";
ofDrawBitmapString(info, startLine+tortoisePos,ofGetHeight()/2+100);
ofSetColor(255, 255, 255, 255);
}
You typically pick a base framerate (one you expect your app to hopefully run at), usually in games it is 30FPS or 60FPS. In this codelet i picked 60FPS as my base. You see that the Hare goes crazy at first as the framerate is above 60FPS, then as i force the framerate lower and lower the Hare gets slower and slower. Meanwhile the Tortoise keeps a constant speed.
As the framerate gets to 10FPS you will see the graphics flickering…achieving framerate independence does not make the underlying graphics update smoother, if FPS is below 30 you will see the screen update.
In a real app as you pile on your graphics and CPU load, the framerate obviously drops, and if your car movement isn’t framerate independent then it would look like it was going slower, also if the framerate increased ridiculously the car would seem to be going faster. It can also dramatically affects user input, in particular i would expect those playing with ofxKinect and multiple human inputs to be having issues related to this.
PS… there is another way to achieve this. Lets say for moving our car we have a function called movethecar() that is called from the OF update() function. You can simply call you movethecar() routine more than once a frame. If you chose your base framerate to be 60FPS then you call the movethecar() once per frame, if the framerate drops to say 44FPS then you would force it down to 30FPS and call movethecar() twice per frame, if the framerate drops to 21FPS then you would force it to 20FPS and call movethecar() three times per frame. Of course you can only use dividers that produce whole numbers, and that is a disadvantage of that method.
That’s it…