Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Call a function after a certain amount of time?(A5)

This thread is locked; no one can reply to it. rss feed Print
Call a function after a certain amount of time?(A5)
jmasterx
Member #11,410
October 2009

With Allegro and it's queue based approach, is it possible to do the following:

I'm making a GUI API (for games, not an OS) and would like to implement animated buttons. I'd like to be able to create timed events, but, within the class.
example:

    class TextBox
    {
       void changeColor(int color);
    
        void createTimedEvent(func* or something, int ticks);
         void animate()
    {
    
        createTimedEvent(changeColor(red),30);
       
    }
    
    };

So in this example, the timer would call the class instance's changeColor function, with argument red, after 30 ms. Is there a way to do this?

Basically, a function to call a function, which could be a function from a instancable class, wit n arguments, after a given interval has expired.

Thanks

Trent Gamblin
Member #261
April 2000
avatar

You need one or more threads. Real GUIs I have experience have a single UI thread that runs in the background to handle these sorts of things.

jmasterx
Member #11,410
October 2009

So how does it do it on one thread, does it use a counter or something?

Because I noticed animated controls in Windows send lots of WM_TIMER messages

bamccaig
Member #7,536
July 2006
avatar

Can't you just use Allegro 5's timers to keep track of time? From there, it's just a matter of getting the difference in time to whatever classes manage the timed events. I don't think that it makes sense to have a createTimedEvent method on TextBox, mind you. :-X

Trent Gamblin
Member #261
April 2000
avatar

I'm not sure. I'm sure there are a number of ways to do it. Perhaps I'm overthinking it, but you could have a sorted list of events you need to fire off, al_rest until the next one, fire it and any others that share that time, then repeat.

jmasterx
Member #11,410
October 2009

But al_rest would sleep the thread, and while difference seems like a good idea, it feels messy to me as a solution.

Trent Gamblin
Member #261
April 2000
avatar

It's the opposite of messy. But choose to do it however you want.

Thomas Fjellstrom
Member #476
June 2000
avatar

I'd just register a timer, and call your function when you get the timer event. And if you want it to only fire once, just stop the timer before you handle it.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Trent Gamblin
Member #261
April 2000
avatar

That works, but I was assuming he was going to want to register for multiple events to happen in the future. In that case, having a list of function pointers or something, and calling them as time comes up in a separate thread, is much easier than writing a whole bunch of different timers with different code for each.

Thomas Fjellstrom
Member #476
June 2000
avatar

You can do the same thing without the extra thread. Setup the timer each time to fire off the next time any timer is due, and call all timer handlers due at that time. But thats really just an extension of my suggestion.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Trent Gamblin
Member #261
April 2000
avatar

How are you going to tell which timer is supposed to call which method?

IonBlade
Member #3,521
May 2003
avatar

I do this in my game with things like switching game states. For example I have a bunch of UI stuff, and I want them to play a "close" animation before switching the game state, which means I need to either a) send an event when the animations are finished playing, or b) just wait a certain amount of time. I chose B.

I have a global in my program that is set with al_current_time() at the beginning of every frame. Objects then store "time to do X action" values that compare themselves with the current time.

float time = al_current_time();

float time_to_do_something = time + 5.0f; // do something in 5 seconds

while ( blah )
{
    time = al_current_time();

    if ( time >= time_to_do_something )
    {
        DoSomething();
    }
}

To achieve your example I would probably create a class containing a "time to do action" variable, a function pointer/functor, and some data to pass. On calling createTimedEvent() I would new one of these classes and it add it to a list that the class is keeping track of.

The following is all pseudo-code, but createTimedEvent() might look something like this:

void MyClass::createTimedEvent( function *func, void *data, float delay )
{
    TimedEvent e = new TimedEvent( func, data, delay );
    timedEventList.push_back( e );
}

Then you'd check your list every frame.

#SelectExpand
1// in your class's update function... 2 3for ( auto i = timedEventList.begin(); i != timedEventList.end(); ) 4{ 5 if ( time >= (*i)->GetActivationTime() ) 6 { 7 (*i)->Activate(); // this would tell (*i) to call its functor, passing the data it is storing 8 9 // now delete the event and remove it from the list. 10 // if you wanted to be fancy, you could have events that repeat 11 // every X amount of time, at which point you could call something 12 // like (*i)->RefreshTime() instead of deleting it. that function 13 // could also increment a counter variable inside the event that 14 // keeps track of HOW MANY times to repeat, even... or just 15 // let it go forever. anyway, here i would just be deleting it. 16 17 delete (*i); 18 i = timedEventList.erase( i ); 19 } 20 else 21 i++; 22}

------

"I've got to choose my words carefully so that I'm not misunderstood, but I think there are fewer developers around today who think about making a good game. As a creator, I find that sad..." - Hideo Kojima

Thomas Fjellstrom
Member #476
June 2000
avatar

How are you going to tell which timer is supposed to call which method?

One option: Timers are stored by their interval. You program the one and only REAL timer to fire when the first virtual timer wants to tick, and call all of the ones that want to go off near that time, then you reprogram the real timer to go off at the next virtual timer interval. It may actually be similar to how A4 does it.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

bamccaig
Member #7,536
July 2006
avatar

I would have thought that you could just run a single timer at the lowest reasonable rate and work around the frame rate, draw rate, and timed events based on that.

Elias
Member #358
May 2000

One option: Timers are stored by their interval. You program the one and only REAL timer to fire when the first virtual timer wants to tick, and call all of the ones that want to go off near that time, then you reprogram the real timer to go off at the next virtual timer interval. It may actually be similar to how A4 does it.

Another option: Use one timer for each event. When you get a timer event, compare the event source to each timer. If it is the same you know it's the one which went off.

--
"Either help out or stop whining" - Evert

BAF
Member #2,981
December 2002
avatar

Don't be so scared of creating new threads. If it works out best to handle the animations in the background, then do it. Creating new threads is essentially free.

Go to: