![]() |
|
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. 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 Agui GUI API -> https://github.com/jmasterx/Agui |
Trent Gamblin
Member #261
April 2000
![]() |
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 Agui GUI API -> https://github.com/jmasterx/Agui |
bamccaig
Member #7,536
July 2006
![]() |
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. -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
Trent Gamblin
Member #261
April 2000
![]() |
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. Agui GUI API -> https://github.com/jmasterx/Agui |
Trent Gamblin
Member #261
April 2000
![]() |
It's the opposite of messy. But choose to do it however you want.
|
Thomas Fjellstrom
Member #476
June 2000
![]() |
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. -- |
Trent Gamblin
Member #261
April 2000
![]() |
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
![]() |
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. -- |
Trent Gamblin
Member #261
April 2000
![]() |
How are you going to tell which timer is supposed to call which method?
|
IonBlade
Member #3,521
May 2003
![]() |
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. 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: Then you'd check your list every frame. 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
![]() |
Trent Gamblin said: 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. -- |
bamccaig
Member #7,536
July 2006
![]() |
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. -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
Elias
Member #358
May 2000
|
Thomas Fjellstrom said: 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. -- |
BAF
Member #2,981
December 2002
![]() |
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. |
|