Timer
s in any language can hang up. That's why I always have some Updateable
class that uses a given library's Timer
. In the constructor for Updateable
, you can tell Updateable
the interval in which it should call a virtual
(overridable) function.
In order to account for slow downs, Updateable
needs to store the last time in which the Timer
fired. Then, when the Timer
fires again, Updateable
simply subtracts the current time from the previous time. That is your deltaTime. You then store the previous time, and the process continues.
Here is some code for my solution in Qt and C++
// This class handles is an abstraction between Timer objects and their logic.
class UpdateComponent : private QObject {
Q_OBJECT
public:
UpdateComponent();
boost::signals2::signal<void (float)> onUpdate;
private Q_SLOTS:
void onTimerUpdate();
private:
QTimer* m_timer;
QDateTime m_previousDateTime;
static const int UPDATE_INTERVAL = 17; // This can be changed through the constructor, for example. This means let the timer fire every 17 milliseconds, or roughly, 60 times per second.
};
// Constructor
UpdateComponent::UpdateComponent() {
m_timer = new QTimer(); // Create a new QTimer
connect(m_timer, SIGNAL(timeout()), this, SLOT(onTimerUpdate())); // Tell m_timer to call this class's function, onTimerUpdate().
m_timer->start(UPDATE_INTERVAL); // Start the timer. It will now begin to fire every ~17 milliseconds.
m_previousDateTime = QDateTime::currentDateTime(); // Store the previous time.
}
// Fired by the timer every UPDATE_INTERVAL (17 milliseconds)
void UpdateComponent::onTimerUpdate() {
QDateTime currentDateTime = QDateTime::currentDateTime(); // Store the current time.
qint64 deltaTimeMilliseconds = m_previousDateTime.msecsTo(currentDateTime); // Find the delta time in milliseconds.
m_previousDateTime = currentDateTime; // Make the previous time the current time.
float deltaTime = deltaTimeMilliseconds/1000.0f; // Convert the delta time into a float with the unit being seconds, instead of milliseconds.
onUpdate(deltaTime); // This is boost::signals2::signal's way of saying, call everyone that is listening to onUpdate, and pass the parameter deltaTime.
}
Here is a class that will listen to UpdateComponent
's onUpdate(float)
function.
class Updateable {
public:
Updateable();
Components::UpdateComponent* getUpdateComponent();
protected :
virtual void onUpdate(float deltaTime) = 0;
Components::UpdateComponent* m_updateComponent;
};
Updateable::Updateable() {
m_updateComponent = new UpdateComponent();
m_updateComponent->onUpdate.connect(boost::bind(&Updateable::onUpdate, this, _1));
}
UpdateComponent* Updateable::getUpdateComponent() {
return m_updateComponent;
}
Any class that is Updateable
can implement the virtual
function onUpdate(float deltaTime)
. onUpdate(float deltaTime)
is called automagically in the derived class, such that its sole parameter tells you the time, in seconds, since the last time the timer was fired. Note that an Updateable
object tries to fire as close to the specified interval as possible, but we make up for any slow-downs or speed-ups. 90% of the timer, you should be getting the interval you specified; however, that 10% of the time where there is a slow-down, or if a Timer
prematurely fires, we account for it.