• Advertisement
Sign in to follow this  

how to use Timer ?

This topic is 4682 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I try to write Text-Base RGP (console application), and i want every 5 seconds my character HP(hit point) increase +1. it would be nice if you include source code. Thanks you in advance.

Share this post


Link to post
Share on other sites
Advertisement
Off the top of my head. Should print "foo." on a line every 5 seconds. Visual C++ doesn't like the templated recursion, so I can't test it myself :/

Still, there's probably more elegant ways than this, even on these forums. Take a look around. Timers are a common topic.


#include <vector>
#include <iostream>

using namespace std;

struct print_foo{
void operator()(){
cout << "foo.\n";
}
};

template <typename F>
struct time_triggered_repeating_event{
long counter;
long reset;
F func;
void trigger(){
while (counter < 0){
func();
counter=counter+reset;
trigger();
}
}
time_triggered_repeating_event(DWORD per_time):counter(0),reset(per_time){}
};

struct modify_and_trigger{
DWORD time_ptr;
DWORD time_difference;
void operator()(time_triggered_repeating_event &event){
event.counter=event.counter-time_difference;
event.trigger();
}
modify_and_trigger(DWORD intime):time_difference(0),time_ptr(intime){}
void update(DWORD newtime){
time_difference=newtime-time_ptr;
time_ptr=newtime;
}
};

int main(){

modify_and_trigger time_tracker(GetTickCount());
vector<time_triggered_repeating_event<print_foo> > timers;
time_triggered_repeating_event<print_foo> five_second_foo(5000);

timers.push_back(five_second_foo);
while (1){
time_tracker.update(GetTickCount());
for_each(timers.begin(),timers.end(),time_tracker);
}
}




[edit: actually, the time_triggered_repeating_event should probably take an optional object F to copy in rather than the default object... ]

Share this post


Link to post
Share on other sites
Good solution!
Maybe add a Sleep(1) so your CPU usage doesn't go berserk if that's the only thing the loop does.

Of course, care has to be taken not halt the loop in a cin >> userinput; (or scanf() for the C guys) since it would pause the timer until the user has made some input. Don't know it from the top of my head, but there's probably some kbhit() equivalent which allows you to check whethere there are waiting keystrokes in the input buffer that you can use to only read input from the console when the user actually has typed something.

-Markus-

Share this post


Link to post
Share on other sites
Thanks Telastyn for fast reply, but there was error in your code.

Share this post


Link to post
Share on other sites
Here's a cooperative single-threaded scheduler for you.


Scheduler.cc
#include "Scheduler.h"

#include <sys/time.h>

#include <deque>
#include <algorithm>
#include <functional>
#include <iostream>

//////////////////////////////////////////////////////////////////////

namespace
{
struct EventPtrCompare :
std::binary_function<Event*, Event*, bool>

{
bool operator()(Event* lhs, Event* rhs) const
{
return rhs->time < lhs->time;
}
};


struct EventPtrDelete :
std::unary_function<Event*, void>
{
void operator()(Event* e) const { delete e; }
};
}

//////////////////////////////////////////////////////////////////////

namespace
{
const EventTime max_time = (EventTime)std::numeric_limits<time_t>::max() +
(EventTime)std::numeric_limits<suseconds_t>::max() * 1e-6;

const EventTime min_time = (EventTime)std::numeric_limits<time_t>::min() +
(EventTime)std::numeric_limits<suseconds_t>::min() * 1e-6;

void advance_time(EventTime& time, EventTime adj)
{
if(time + adj > max_time)
{
time -= (max_time - min_time);
time += adj _time;
}
else
time += adj;
}

EventTime get_time()
{
timeval time;
gettimeofday(&time, 0);

return (EventTime)time.tv_sec + 1e-6 * time.tv_usec;
}
}


Scheduler::Scheduler() :
last_run(get_time())
{
}

Scheduler::~Scheduler()
{
for_each(queue.begin(), queue.end(), EventPtrDelete());
for_each(overflow.begin(), overflow.end(), EventPtrDelete());
}

void Scheduler::schedule(void (*action)() )
{
Event e = { action, get_time(), 0, 0 };

schedule( new Event(e) );
}

void Scheduler::schedule(Event e)
{
if (e.time == 0) e.time = get_time();
schedule( new Event(e) );
}

void Scheduler::schedule(Event* e)
{
queue_t& q = (e->time < last_run) ? overflow : queue;

// insert in the appropriate queue
q.push_back(e);
std::push_heap(q.begin(), q.end(), EventPtrCompare());
}

void Scheduler::process(EventTime now)
{
Event* e = queue.front();

std::cerr << '(' << now << ") \t"
<< (void*)e->action << ' '
<< e->time << ' '
<< e->count << ' '
<< e->period << "\t";

(e->action)();

// Remove from queue
std::pop_heap(queue.begin(), queue.end(), EventPtrCompare());
queue.pop_back();

if(e->count > 0)
{
--e->count;

// Dead, don't reschedule
if(e->count == 0)
{
delete e;
return;
}
}

if(e->period == 0)
e->time = now;
else
advance_time(e->time, e->period);

std::cerr << (void*)e->action << ' '
<< e->time << ' '
<< e->count << ' '
<< e->period << std::endl;


// Reinsert in queue
schedule(e);
}

void Scheduler::run()
{
EventTime now = get_time();

if(now<last_run) // Timer wrap-around
{
while( !queue.empty() )
process(now);

queue.swap(overflow);
}

while( !queue.empty() &&
queue.front()->time <= now )
process(now);

last_run = now;
}









Scheduler.h

#include <deque>

typedef double EventTime;

struct Event
{
void (*action)();
EventTime time;

unsigned long count;
EventTime period;
};

class Scheduler
{
// not using q priority queue because I want to be able to swap them
typedef std::deque<Event*> queue_t;

queue_t queue;
queue_t overflow;

EventTime last_run;

public:
Scheduler();
~Scheduler();

public:
void schedule(void (*action)());
void schedule(Event event);
void run();

private:
void schedule(Event* event);
void process(EventTime now);

private:
// Scheduler object is non-copyable
Scheduler(const Scheduler&);
Scheduler& operator=(const Scheduler);
};








foo.cc

#include "Scheduler.h"

#include <iostream>
#include <iomanip>
#include <string>

Scheduler scheduler;

int hp = 0;
const int max_hp = 50;

void hpregen()
{
hp = std::min( hp + 5, max_hp );
}

Event hpregen_event = { hpregen, 0, 0, 5 };

void read_command(std::string line)
{
std::cout << "HP: " << hp << "/" << max_hp << " >";
std::getline( std::cin, line );
}

void execute_command(const std::string& line)
{
std::cout << "You have typed \"" << line << "\"" << std::endl;
}

int main()
{
scheduler.schedule( hpregen_event );

std::string line;

while( true )
{
read_command(line);
scheduler.run();
execute_command(line);
scheduler.run();
}
}







The timer ticks even when the program is waiting on input though, since it is single threaded, the events are only processed when you call run(), at which point all the past due events are rushed. So, for example, if you wait 20 seconds before pressing return, the hpregen() function will be called 3 or 4 times in a row (depending on how the events fall in the period).

The parameters of the Event structure are: function to call, delay until first call (seconds), number of times the even is scheduled (0 = infinite), delay until rescheduling (0 = "now").

Also, note that I use the Linux gettimeofday() timer. If you're a Windows user, switch to timeGetTime() or QueryPerformanceCounter().

I also deal with timer overflow. Correctly, I hope. [smile]

Share this post


Link to post
Share on other sites
Quote:
Original post by invisal
Thanks Telastyn for fast reply, but there was error in your code.



Eh, yeah, I think for_each requires a header I didn't specify. Still, Fruny's solution looks more complete.

[edit: cygon: Or use select() as the triggering mechanism]

Share this post


Link to post
Share on other sites
could someone explain this code for me?

struct print_foo{
void operator()(){
cout << "foo.\n";
}
};
/*I understand struct, and I think I understand overloading operators but what this code does, I dont understand
*/




if you could explain it that would be great

Share this post


Link to post
Share on other sites
Quote:
Original post by donjonson
could someone explain this code for me?
*** Source Snippet Removed ***

if you could explain it that would be great



Certainly!

So this is a "functor". That's the keyword for searches, and the term most folks will use.

What this code does is declare a structure [or a type if you prefer] which behaves like a function. Just like classes, it's just a type, so you can't call print_foo() and expect it to print "foo". You need to actually make an object:


print_foo a;
print_foo b;


a() will then print foo. As will b().

This in and of itself isn't too astounding. Consider this code though:



struct print_something{
string s;
void operator()(){
cout << s << endl;
}
print_something(const char *c):s(c){}
};



Now the functor has a constructor. It also contains a state [the string]. This way you can store parameters to a function in an instance of the function. For example:


print_something a("foo");
print_something b("bar");


Now, running a() will print foo, but running b() will print bar. These objects a and b can be passed around like any other object. Something like this is commonly used in UI code to store "actions" for when buttons are clicked. Also, since functors are just normal objects, they work well with templates.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement