I have a recursive function in C++ and I need to immediately terminate the function including all calls which have recursively made after a specific time, say 60 secs.
I have tried the following but doesn't work. takesTooLong is a global variable but if its value changes to 1 in one call, other calls keep seeing it as 0.
The OS is Ubuntu 12.10.
main() is something like this:
int main()
{
takesTooLong = 0;
startTime = clock();
RecursiveFunction();
endTime = clock();
printf("Elapsed time: %f", CalculateElapsedTime(startTime, endTime));
return 0;
}
My recursive function:
void RecursiveFunction(Some Parameters)
{
if (takesTooLong == 1)
return;
endTime = clock();
differenceTime = CalculateElapsedTime(startTime, endTime);
if (differenceTime > MAX_SECONDS)
{
takesTooLong = 1;
}
if (takesTooLong == 0)
{
for (i = 0; i < n && takesTooLong == 0; i++)
{
RecursiveFunction(Some Updated Parameters);
}
}
}
Pseudocode:
typedef ??? Time;//time type
Time getCurrentTime(); //returns time. Or ticks. Anything you could use to measure time.
void recursiveFunction(Time startTime){
...//do something here
Time currentTime = getCurrentTime();
if ((currentTime - startTime) > limit)
return;
recursiveFunction(startTime);
}
void recursiveFunction(){
Time startTime = getCurrentTime();
recursiveFunction(startTime);
}
Yes, you still have to unroll the stack but the alternatives are all ugly, the best probably being longjmp. If you need greater resolution than seconds, or you want to measure process/kernel time rather than wall clock time, use alternatives like timer_create or setitimer.
void alarmHandler (int sig)
{
timedOut = 1;
}
signal(SIGALRM, alarmHandler);
alarm(60);
RecursiveFunction();
alarm(0);
if (timedOut)
{
//report something
timedOut = 0;
}
void RecursiveFunction(Some Parameters)
{
if (timedOut)
return;
//........
}
The easiest way to exit an unknown number of recursions is by throwing an exception. Since you're doing it at most once every 60 seconds, this isn't too bad. Just make it a class TimeLimitExceeded : public std::runtime_error and catch that in the top level wrapper†.
† Most recursive functions should not be called directly, but via a non-recursive wrapper. The signature of the recursive function usually is inconvenient for callers, as it contains implementation details that are irrelevant to the caller.
Related
What would be the best way to add a chronometer because this type of chronometer that I invented makes my game snake advance in 1 second and its really slow
void timer()
{
int g = 1;
int h = 0;
while (g != 0)
{
Sleep(1000);
h = h + 1;
gotoxy(50, 1); printf("Tiempo: %d",h);
}
}
Some pseudo-code to give you an idea of how it could be done:
time_type last_time = now(); // Initialize to the current time
// Main game loop
forever
{
// Do other game-related things...
// Now handle things that should be done on regular intervals
time_type current_time = now();
time_diff_type difference = current_time - last_time;
if (difference > 2 second)
{
// Do things that should be done every two seconds
}
if (difference > 1 second)
{
// Do things that should be done every second
}
last_time = current_time;
}
For the time_type and now functions, use the functionality in std::chrono.
For example, to get the current time do e.g.
auto current_time = std::chrono::system_clock::now();
And with a newer compiler and a using namespace std::literals::chrono_literals; you could actually use e.g. 1s as a second:
auto difference = current_time - last_time;
if (difference > 1s) { /* Code here... */ }
The above is valid C++ code.
Describtion of the problem:
we need to call a function in extern process as fast as possible. Boost interprocess shared memory is used for communication. The extern process is either mpi master or a single executable. The calculation time of the function lies between 1ms and 1s. The function should be called up to 10^8-10^9 times.
I've tried a lot of possibilities, but I still have some problems with each of them. Here I introduce two of best working implementations
Version 1 ( using intreprocess conditions )
Main-process
bool calculate(double& result, std::vector<double> c){
// data_ptr is a structure in shared memoty
data_ptr_->validCalculation = false;
bool timeout = false;
// write data (cVec_ is a vector in shared memory )
cVec_->clear();
for (int i = 0; i < c.size(); ++i)
{
cVec_->push_back(c[i]);
}
// cond_input_data is boost interprocess condition
data_ptr_->cond_input_data.notify_one();
boost::system_time const waittime = boost::get_system_time() + boost::posix_time::seconds(maxWaitTime_in_sec);
// lock slave process
scoped_lock<interprocess_mutex> lock_output(data_ptr_->mutex_output);
// wait till data calculated
timeout = !(data_ptr_->cond_output_data.timed_wait(lock_output, waittime)); // true if timeout, false if no timeout
if (!timeout)
{
// get result
result = *result_;
return data_ptr_->validCalculation;
}
else
{
return false;
}
};
Extern process runs a while-loop ( till abort condition is fullfilled)
do {
scoped_lock<interprocess_mutex> lock_input(data_ptr_->mutex_input);
boost::system_time const waittime = boost::get_system_time() + boost::posix_time::seconds(maxWaitTime_in_sec);
timeout = !(data_ptr_->cond_input_data.timed_wait(lock_input, waittime)); // true if timeout, false if no timeout
if (!timeout)
{
if (!*abort_flag_) {
c.clear();
for (int i = 0; i < (*cVec_).size(); ++i) //Insert data in the vector
{
c.push_back(cVec_->at(i));
}
// calculate value
if (call_of_function_here(result, c)) { // valid calculation ?
*result_ = result;
data_ptr_->validCalculation = true;
}
}
}
//Notify the other process that the data is avalible or we dont get the input data
data_ptr_->cond_output_data.notify_one();
} while (!*abort_flag_); // while abort flag is not set, check if some values should be calculated
This is best working version, but sometimes it holds up, if the calculation time is short (~1ms). I assume, it happens, if main-process reaches
data_ptr_->cond_input_data.notify_one();
earlier, than extern process is waiting on
timeout = !(data_ptr_->cond_input_data.timed_wait(lock_input, waittime));
waiting condition. So we have probably some kind of synchronisation problem.
Second condition does not help ( i.e. wait only if input data not set, similar to the anonymous condition example with message_in flag). Since, it is still possible, that one process notify the other one, before the second one is waiting for notification.
Version 2 ( using boolean flag and while loop with some delay )
Main-process
bool calculate(double& result, std::vector<double> c){
data_ptr_->validCalculation = false;
bool timeout = false;
// write data
cVec_->clear();
for (int i = 0; i < c.size(); ++i) //Insert data in the vector
{
cVec_->push_back(c[i]);
}
// this is the flag in shared memory used for communication
*calc_flag_ = true;
clock_t test_begin = clock();
clock_t calc_time_begin = clock();
do
{
calc_time_begin = clock();
boost::this_thread::sleep(boost::posix_time::milliseconds(while_loop_delay_m_s));
// wait till data calculated
timeout = (double(calc_time_begin - test_begin) / CLOCKS_PER_SEC > maxWaitTime_in_sec);
} while (*(calc_flag_) && !timeout);
if (!timeout)
{
// get result
result = *result_;
return data_ptr_->validCalculation;
}
else
{
return false;
}
};
and the extern process
do {
// we wait till input data is set
wait_begin = clock();
do
{
wait_end = clock();
timeout = (double(wait_end - wait_begin) / CLOCKS_PER_SEC > maxWaitTime_in_sec);
boost::this_thread::sleep(boost::posix_time::milliseconds(while_loop_delay_m_s));
} while (!(*calc_flag_) && !(*abort_flag_) && !timeout);
if (!timeout)
{
if (!*abort_flag_) {
c.clear();
for (int i = 0; i < (*cVec_).size(); ++i) //Insert data in the vector
{
c.push_back(cVec_->at(i));
}
// calculate value
if (call_of_local_function(result, c)) { // valid calculation ?
*result_ = result;
data_ptr_->validCalculation = true;
}
}
}
//Notify the other process that the data is avalible or we dont get the input data
*calc_flag_ = false;
} while (!*abort_flag_); // while abort flag is not set, check if some values should be calculated
The problem in this version is the delay-time. Since we have calculation times close to 1ms, we have to set the delay at least to this value. For smaller delays the cpu-load is high, for higher delays we lose a lot of performance due to not necessary waiting time
Do you have an idea how to improve one of this versions? or may be there is a better solution?
thx.
I'm trying to use the given code within steptimer.h to set up code that will run every two seconds. However with the code below, timer.GetTotalSeconds() always returns 0.
Unfortunately there isn't much information readily available on StepTimer.h (at least I believe due to a lack of useful search results), so I was hoping someone might be able to shed some light as to why the timer isn't recording the elapsed seconds. Am I using it incorrectly?
Code from Game.h, Game.cpp and StepTimer.h are included below. Any help is greatly appreciated.
From Game.cpp:
double time = timer.GetTotalSeconds();
if (time >= 2) {
laser_power++;
timer.ResetElapsedTime();
}
Initialised in Game.h:
DX::StepTimer timer;
From Common/StepTimer.h:
#pragma once
#include <wrl.h>
namespace DX
{
// Helper class for animation and simulation timing.
class StepTimer
{
public:
StepTimer() :
m_elapsedTicks(0),
m_totalTicks(0),
m_leftOverTicks(0),
m_frameCount(0),
m_framesPerSecond(0),
m_framesThisSecond(0),
m_qpcSecondCounter(0),
m_isFixedTimeStep(false),
m_targetElapsedTicks(TicksPerSecond / 60)
{
if (!QueryPerformanceFrequency(&m_qpcFrequency))
{
throw ref new Platform::FailureException();
}
if (!QueryPerformanceCounter(&m_qpcLastTime))
{
throw ref new Platform::FailureException();
}
// Initialize max delta to 1/10 of a second.
m_qpcMaxDelta = m_qpcFrequency.QuadPart / 10;
}
// Get elapsed time since the previous Update call.
uint64 GetElapsedTicks() const { return m_elapsedTicks; }
double GetElapsedSeconds() const { return TicksToSeconds(m_elapsedTicks); }
// Get total time since the start of the program.
uint64 GetTotalTicks() const { return m_totalTicks; }
double GetTotalSeconds() const { return TicksToSeconds(m_totalTicks); }
// Get total number of updates since start of the program.
uint32 GetFrameCount() const { return m_frameCount; }
// Get the current framerate.
uint32 GetFramesPerSecond() const { return m_framesPerSecond; }
// Set whether to use fixed or variable timestep mode.
void SetFixedTimeStep(bool isFixedTimestep) { m_isFixedTimeStep = isFixedTimestep; }
// Set how often to call Update when in fixed timestep mode.
void SetTargetElapsedTicks(uint64 targetElapsed) { m_targetElapsedTicks = targetElapsed; }
void SetTargetElapsedSeconds(double targetElapsed) { m_targetElapsedTicks = SecondsToTicks(targetElapsed); }
// Integer format represents time using 10,000,000 ticks per second.
static const uint64 TicksPerSecond = 10000000;
static double TicksToSeconds(uint64 ticks) { return static_cast<double>(ticks) / TicksPerSecond; }
static uint64 SecondsToTicks(double seconds) { return static_cast<uint64>(seconds * TicksPerSecond); }
// After an intentional timing discontinuity (for instance a blocking IO operation)
// call this to avoid having the fixed timestep logic attempt a set of catch-up
// Update calls.
void ResetElapsedTime()
{
if (!QueryPerformanceCounter(&m_qpcLastTime))
{
throw ref new Platform::FailureException();
}
m_leftOverTicks = 0;
m_framesPerSecond = 0;
m_framesThisSecond = 0;
m_qpcSecondCounter = 0;
}
// Update timer state, calling the specified Update function the appropriate number of times.
template<typename TUpdate>
void Tick(const TUpdate& update)
{
// Query the current time.
LARGE_INTEGER currentTime;
if (!QueryPerformanceCounter(¤tTime))
{
throw ref new Platform::FailureException();
}
uint64 timeDelta = currentTime.QuadPart - m_qpcLastTime.QuadPart;
m_qpcLastTime = currentTime;
m_qpcSecondCounter += timeDelta;
// Clamp excessively large time deltas (e.g. after paused in the debugger).
if (timeDelta > m_qpcMaxDelta)
{
timeDelta = m_qpcMaxDelta;
}
// Convert QPC units into a canonical tick format. This cannot overflow due to the previous clamp.
timeDelta *= TicksPerSecond;
timeDelta /= m_qpcFrequency.QuadPart;
uint32 lastFrameCount = m_frameCount;
if (m_isFixedTimeStep)
{
// Fixed timestep update logic
// If the app is running very close to the target elapsed time (within 1/4 of a millisecond) just clamp
// the clock to exactly match the target value. This prevents tiny and irrelevant errors
// from accumulating over time. Without this clamping, a game that requested a 60 fps
// fixed update, running with vsync enabled on a 59.94 NTSC display, would eventually
// accumulate enough tiny errors that it would drop a frame. It is better to just round
// small deviations down to zero to leave things running smoothly.
if (abs(static_cast<int64>(timeDelta - m_targetElapsedTicks)) < TicksPerSecond / 4000)
{
timeDelta = m_targetElapsedTicks;
}
m_leftOverTicks += timeDelta;
while (m_leftOverTicks >= m_targetElapsedTicks)
{
m_elapsedTicks = m_targetElapsedTicks;
m_totalTicks += m_targetElapsedTicks;
m_leftOverTicks -= m_targetElapsedTicks;
m_frameCount++;
update();
}
}
else
{
// Variable timestep update logic.
m_elapsedTicks = timeDelta;
m_totalTicks += timeDelta;
m_leftOverTicks = 0;
m_frameCount++;
update();
}
// Track the current framerate.
if (m_frameCount != lastFrameCount)
{
m_framesThisSecond++;
}
if (m_qpcSecondCounter >= static_cast<uint64>(m_qpcFrequency.QuadPart))
{
m_framesPerSecond = m_framesThisSecond;
m_framesThisSecond = 0;
m_qpcSecondCounter %= m_qpcFrequency.QuadPart;
}
}
private:
// Source timing data uses QPC units.
LARGE_INTEGER m_qpcFrequency;
LARGE_INTEGER m_qpcLastTime;
uint64 m_qpcMaxDelta;
// Derived timing data uses a canonical tick format.
uint64 m_elapsedTicks;
uint64 m_totalTicks;
uint64 m_leftOverTicks;
// Members for tracking the framerate.
uint32 m_frameCount;
uint32 m_framesPerSecond;
uint32 m_framesThisSecond;
uint64 m_qpcSecondCounter;
// Members for configuring fixed timestep mode.
bool m_isFixedTimeStep;
uint64 m_targetElapsedTicks;
};
}
Alrighty got what I wanted with the code below. Was missing the .Tick(####) call.
timer.Tick([&]() {
double time = timer.GetTotalSeconds();
if (time >= checkpt) {
laser_power++;
checkpt += 2;
}
});
Just fixed an integer checkpt to increment by 2 each time so that it runs every 2 seconds. There's probably a better way to do it, but it's 3.30am so I'm being lazy for the sake of putting my mind at ease.
i'm working on gesture recognition application and i would like to implement timer but i don't know how.
here is what i want to do: user should be showing one gesture for 3 seconds before next function happens.
now it looks like this:
if(left_index==1)
{
putText("correct",Point(95,195),FONT_HERSHEY_COMPLEX_SMALL,0.8,Scalar(0,255,0),1,CV_AA);
correct = true;
}
break;
i would like it to be like this: if(left_index==1) <- if this is true for 3 seconds than the {} happens.
thank you for help.
there is a built-in function called sleep. It will kind of put your program at rest for int x milliseconds
I will make a function wait(int seconds):
void wait(long seconds)
{
seconds = seconds * 1000;
sleep(seconds);
}
wait(1); //waits for 1 second or 1000 milliseconds
You could try the following:
#include <time.h>
#include <unistd.h>
// Whatever your context is ...
if(left_index==1)
{
clock_t init, now;
init=clock();
now=clock();
while((left_index==1) && ((now-init) / CLOCKS_PER_SEC) < 3))
{
sleep(100); // give other threads a chance!
now=clock();
}
if((left_index==1) && (now-init) / CLOCKS_PER_SEC) >= 3))
{
// proceed with stuff
putText
( "correct"
, Point(95,195)
, FONT_HERSHEY_COMPLEX_SMALL,0.8,Scalar(0,255,0),1,CV_AA);
correct = true;
}
}
For c++11 I'd prefer a solution involving the classes from std::chrono instead working with time.h.
Also, you can try doing the following :
#include <time.h>
clock_t init, final;
init=clock();
//
// do stuff
//
final=clock()-init;
cout << (double)final / ((double)CLOCKS_PER_SEC);
Check these links out for further reference :
http://www.cplusplus.com/forum/beginner/317/
http://www.cplusplus.com/reference/ctime/
assuming your app is running an update loop.
bool gesture_testing = false;
std::chrono::time_point time_start;
while(app_running) {
if (! gesture_testing) {
if (left_index == 1) {
gesture_testing = true;
time_start = std::chrono::high_resolution_clock::now();
}
} else {
if (left_index != 1) {
gesture_testing = false;
} else {
auto time_end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::seconds>(time_end - time_start);
if (duration.count() == 3) {
// do gesture function
gesture_testing = false;
}
}
}
}
this is the basic logic, you can write a timer class and refactor the body into one function to make room for other part of your app.
I am designing a time class that will only perform an action after a predefined time but I still cannot figure out the way to reset the time. Is that anyway to reset the time back to zero or temporarily stop and resume the time?
so, my goal is to reset the time each time the condtion A meets so that it won't screw up delayTime function that it still keep the previous time and end up wrong time calculation.
if ( condition A )
{
if ( time.delayTime( 5.0f ) )
{
doActionA();
}
}
TimeClass.h
#ifndef _TIMECLASS_H_
#define _TIMECLASS_H_
#include <windows.h>
class TimeClass
{
public:
TimeClass();
~TimeClass();
bool delayTime( float second );
float getSecond();
void reset();
private:
float getGameTime();
float currentTime;
UINT64 ticks;
float time;
float timeAtGameStart;
UINT64 ticksPerSecond;
};
#endif
TimeClass.cpp
#include "TimeClass.h"
TimeClass::TimeClass()
{
// We need to know how often the clock is updated
if( !QueryPerformanceFrequency((LARGE_INTEGER *)&ticksPerSecond) )
ticksPerSecond = 1000;
// If timeAtGameStart is 0 then we get the time since
// the start of the computer when we call GetGameTime()
timeAtGameStart = 0;
timeAtGameStart = getGameTime();
}
float TimeClass::getGameTime()
{
// This is the number of clock ticks since start
if( !QueryPerformanceCounter((LARGE_INTEGER *)&ticks) )
ticks = (UINT64)timeGetTime();
// Divide by frequency to get the time in seconds
time = (float)(__int64)ticks/(float)(__int64)ticksPerSecond;
// Subtract the time at game start to get
// the time since the game started
time -= timeAtGameStart;
return time;
}
bool TimeClass::delayTime( float second )
{
currentTime = getGameTime();
static float totalTime = second + getGameTime();
if ( currentTime >= totalTime )
{
totalTime = second + getGameTime();
return true;
}
else
{
return false;
}
}
float TimeClass::getSecond()
{
currentTime = getGameTime();
static float totalTime = 1 + getGameTime();
if ( currentTime >= totalTime )
{
totalTime = 1 + getGameTime();
return currentTime;
}
else
{
return currentTime;
}
}
void TimeClass::reset()
{
timeAtGameStart = 0;
timeAtGameStart = getGameTime();
}
TimeClass::~TimeClass()
{
}
Standard Library
As already stated simply use the std::chrono::high_resolution_clock. If you use the Visual C++ Compiler there is an actual bug report on the resolution of the high_resolution_clock and it's NOT the same as the QueryPerformanceCounter.
Example
auto t1 = std::chrono::high_resolution_clock::now();
// Do something
auto t2 = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1);
double dt = duration.count();
TimeClass
The main problem you're facing right now is that you are using static variables. You are looking for a way to reset the static variable from another function than the delayTime. If you would introduce member variables to get rid of the static variables it would make things a lot easier (Note: static variables within functions are bad practice as they are holding the state => bad for multi-threading). Well what about something like this:
class Event {
std::chrono::high_resolution_clock::time_point lastEventOccurred;
double timeBetweenEvents;
public:
Event(double timeBetweenEvents)
: timeBetweenEvents(timeBetweenEvents)
, lastEventOccurred(std::chrono::high_resolution_clock::now()) { }
bool ready() {
auto currentTime = std::chrono::high_resolution_clock::now();
auto elapsedTime = std::chrono::duration_cast<std::chrono::duration<double>>(currentTime - lastEventOccurred).count();
if(elapsedTime > timeBetweenEvents) {
reset();
return true;
} else
return false;
}
void reset() {
lastEventOccurred = std::chrono::high_resolution_clock::now();
}
};
Usage:
Event evtDelay = Event(5.0);
if(condition A) {
if(evtDelay.ready()) {
doActionA();
}
} else if(condition B) {
evtDelay.reset();
}
Another approach would be to use a capturing state and an update method. As I can see you are using this for a game so the updating could be done in the update method of your game. Assuming the event would have a state like {Active, Inactive} and a member for the elapsed time, every time you call update you add the elapsed time since the last update call if the state is Active. Therefore the ready function would only check if the elapsed time is greater than the defined threshold.
class Event {
std::chrono::high_resolution_clock::time_point lastUpdateCall;
double timeBetweenEvents;
double elapsedTime;
bool active;
public:
Event(double timeBetweenEvents)
: timeBetweenEvents(timeBetweenEvents)
, lastUpdateCall(std::chrono::high_resolution_clock::now())
, elapsedTime(0.0)
, active(true) { }
bool ready() {
return elapsedTime >= timeBetweenEvents;
}
void reset() {
elapsedTime = 0.0;
}
void setActive(bool state) {
active = state;
}
void update() {
auto currentTime = std::chrono::high_resolution_clock::now();
if(active) {
auto dt = std::chrono::duration_cast<std::chrono::duration<double>>(currentTime - lastUpdateCall).count();
elapsedTime += dt;
}
lastUpdateCall = currentTime;
}
};
From your questions it is not quite clear what exactly you want to achieve: clock resetting, pausing/resuming, interval measuring, or timed triggers, or all of this. So I will just describe all of this. =)
Just to make it clear
do not use static variables in member functions (methods), it makes your code harder to understand and error-prone. Instead use class member variables (fields)
do not store time in (milli)seconds float format. I has too low precision. Even double is not recommended. Instead, store it in API-native format: some kind of CPU ticks: let's wrap it in struct time_point and convert to float only when user asks for it:
struct time_point
{
LARGE_INTEGER value;
};
The functions you'll need from your underlying API are:
function to get current time: let's call it
private:
time_point now(); // Here you wrap QueryPerformanceCounter() or `boost::chrono::...::now();` stuff
functions to reinterpret difference (time duration) between two time_point to usable units (such as nanoseconds long long of (milli)seconds float)
private:
float Duration(const time_point& from, const time_point& to); // Here you divide by frequence
(also, you can make time_point class and make this functions members)
All other functions can be API-agnostic.
Following this design, you can abstract out underlying API from user and make your app more portable.
Resetting
Is that anyway to reset the time back to zero
But, wait, you've already implemented "reset the time back to zero":
void TimeClass::reset()
{
//timeAtGameStart = 0;
timeAtGameStart = getGameTime();
}
(timeAtGameStart = 0; commented as it non needed)
You just saying that start is now(), so difference between start and now() becomes zero.
Stopping and resuming
or temporarily stop and resume the time?
you can achieve "time stop/resume" effect by:
adding bool isPaused member varible (don't forget to init it to false in constructor)
adding timePaused member varible (of type of your time units: time_point in my case)
altering your getGameTime() function: when paused it will return timePaused instead of current time
and of course, introducing Pause()/Resume() functions
Here is example code (naming is a little different to yours)
void Pause()
{
if (!isPaused)
{
timePaused = clock::now();
isPaused = true;
}
}
void Resume()
{
if (isPaused)
{
isPaused = false;
start -= clock::now() - timePaused;
}
}
float Now() const
{
if (isPaused)
{
return Duration(start, timePaused);
}
return Duration(start, clock::now()); // basically it is your getGameTime()
}
Delta (basic interval measuring)
Sometimes you will want to know how much time passed between some places in your program. For example, to measure FPS in game, you will need to know delta time between frames.
To implement this we will need members:
time_point prevTick; // time of previous tick
time_point currTick; // time of current tick
void Tick() // user must call it each frame
{
prevTick = currTick;
currTick = clock::now();
}
const float GetDelta() const // user must call it to know frame time
{
return Duration(prevTick, currTick);
}
Stopwatch (advanced interval measuring)
Now, we need to have some kind of timed trigger. It is a good idea to separate this triggerfrom timer, so:
you can have multiple trigger with different start time and different trigger intervals
all of this triggers must be independent from each other
global clocks will not be altered, so all triggers remain valid
So let's wrap it to class:
class Stopwatch
{
private:
float m_Interval;
float m_Time;
float m_PrevTime;
public:
Stopwatch(float interval_ms = 1000.0f) :
m_Interval(interval_ms),
m_Time(0.0f),
m_PrevTime(m_Time)
{}
float GetRefreshInterval() const { return m_Interval; }
void SetRefreshInterval(float interval_ms) { m_Interval = interval_ms; }
// Update as frequent as possible
inline void Update(float dt)
{
m_Time += dt;
}
// Check if time interval reached
inline bool IsAboutTime()
{
if (m_Time >= m_Interval)
{
m_PrevTime = m_Time;
m_Time = 0.0f;
return true;
}
return false;
}
// exact value of last interval
inline float GetLastTime() const
{
return m_PrevTime;
}
};
Usage example:
Stopwatch stopwatch(5000.0f); // will trigger each 5 seconds
...
stopwatch.Update(timer.GetDelta()); // GetDelta() returns time difference between update frames
if ( condition A )
{
if ( stopwatch.IsAboutTime() )
{
doActionA();
}
}
Another possible ways to design stopwatch are:
inherit from clock
pass current time to IsAboutTime() so no need to Update()
Happy coding! =)