Handmade Hero » Forums » Code » Timers In Games
HawYeah
14 posts
#14228 Timers In Games
4 months, 1 week ago Edited by HawYeah on Feb. 8, 2018, 5:05 a.m. Reason: Initial post

Hey guys,

So I've been working on my game for quite a while and there are many instances where we need to wait x amount of frames before we execute (waiting for an animation, etc). In handmade hero, the closest thing to this that I got to was the cutscene code. In that code, casey kept a float of the amount of time elapsed and manually updated this variable for the cutscene state. In my game, I have a timer object that I allocate and each timer is linked together in a linked list so that I can call a single function to update all my timers and not have to worry about forgetting to update a timer in my code. Then anything that needs to time anything just has a pointer to a timer and uses it as needed.

I was wondering how other people handled this in their own applications since casey's method is definitly cleaner in my opinion but you can sometimes forget to increment the float thats accumulating the time. In my case, thats all handled for me but it comes at the cost of having to allocate timers that can fragment memory and have to be deleted. Im debating about switching over to something like what casey did but I wanted to hear how others have gone about this issue before I decide to do anything.
mmozeiko
Mārtiņš Možeiko
1693 posts
1 project
#14229 Timers In Games
4 months, 1 week ago

I pretty much use same system as Casey. Integer/float for time left for event to be active.

I feel worrying about updating this variable is silly. I mean - you can as well forget to update other variables - object position, pixel color, etc.. Its all the same - just some integer or float to update/add/subtract. Yeah, game won't work correctly. That's why you'll debug it, and fix the issue.
ratchetfreak
365 posts
#14230 Timers In Games
4 months, 1 week ago Edited by ratchetfreak on Feb. 8, 2018, 10:33 a.m.

you shouldn't have to increment a float per timer at all.

Instead use uint64 as a current time from starting the application in milliseconds and make each timer object hold a uint64 for when it should be triggered.

That way the code only needs to compare the new current_time against each timer's trigger time. And if you can keep the timers in some kind of ordered structure (a priority queue) so you can peek at the one that needs triggering the soonest and then early out once the top timer doesn't need to be triggered.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Timer* timer;
while(timer_queue_peek(&timer) && timer->trigger_time <= current_time){
    uint64 time_until_next_trigger = timer->func(timer->data);
    if(time_until_next_trigger > 0){ //optimization for recurring events
        timer->trigger_time = timer->trigger_time + time_until_next_trigger;
        timer_queue_push_down();
    } else {
        timer_queue_pop();
    }
}


you can also add a limiter here on how many timers can be triggered per frame to avoid getting stuck in a infinite loop.

By having the timer function return the next time you can make coroutine-like functions in your timers though perhaps having only time as trigger for the next event is a bit limiting.
HawYeah
14 posts
#14237 Timers In Games
4 months, 1 week ago

mmozeiko
I pretty much use same system as Casey. Integer/float for time left for event to be active.

I feel worrying about updating this variable is silly. I mean - you can as well forget to update other variables - object position, pixel color, etc.. Its all the same - just some integer or float to update/add/subtract. Yeah, game won't work correctly. That's why you'll debug it, and fix the issue.


Yeah your right, I realized that it was a dumb thing to worry about and I just finished changing my code to use a float for counting time. It actually ended up simplifying lots of my code that was holding double state and it also simplifyed lots of arguments that I was passing around to different functions. I feel really good about this change, so thanks a lot for the help :)

ratchetfreak
you shouldn't have to increment a float per timer at all.

Instead use uint64 as a current time from starting the application in milliseconds and make each timer object hold a uint64 for when it should be triggered.

That way the code only needs to compare the new current_time against each timer's trigger time. And if you can keep the timers in some kind of ordered structure (a priority queue) so you can peek at the one that needs triggering the soonest and then early out once the top timer doesn't need to be triggered.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Timer* timer;
while(timer_queue_peek(&timer) && timer->trigger_time <= current_time){
    uint64 time_until_next_trigger = timer->func(timer->data);
    if(time_until_next_trigger > 0){ //optimization for recurring events
        timer->trigger_time = timer->trigger_time + time_until_next_trigger;
        timer_queue_push_down();
    } else {
        timer_queue_pop();
    }
}


you can also add a limiter here on how many timers can be triggered per frame to avoid getting stuck in a infinite loop.

By having the timer function return the next time you can make coroutine-like functions in your timers though perhaps having only time as trigger for the next event is a bit limiting.


I was already kinda doing something similar but less rigorously. Instead of making sure that each timers events get executed in the proper order, I just had them execute at the frame that they finish, but potentially out of order. My game is a tower defense so i don't have many precise timings like in maybe other games, and doing what mmozeiko suggested ended up simplifying a lot of my game logic. Thanks for the response anyways :)