Hello!
Is there any comprehensive tutorial on how to use timers? Im making a space-invaders style game and I need to know how to use them... But the current tutorials arent helping. Should I post the code?
Thanks!
Almost all you need to know:
1 | int timer; |
2 | void timer_f() { |
3 | ++timer; |
4 | } |
5 | |
6 | int main() { |
7 | ... |
8 | install_timer(); |
9 | install_int_ex(timer_f, BPS_TO_TIMER(100)); |
10 | timer = 0; |
11 | |
12 | while (!done) { |
13 | // this will happen 100 times per second |
14 | while (timer) { |
15 | do_logic(); |
16 | --timer; |
17 | } |
18 | |
19 | draw_stuff(); |
20 | } |
21 | ... |
22 | } |
EDIT: Made sure timer is 0 before entering the main loop.
Just make sure to set "timer" to 0 before entering the loop shown above.
Can you manage how many times a second should the loop go?
EDIT: Yeah im stupid. Found that out! Thanks!
Yes.
Try clicking the function name in the source code below:
install_int_ex(timer_f, BPS_TO_TIMER(100));
What if I have such code:
If I press escape I cant get out. Should I do it like this:
while(timer || !key[KEY_ESC]) { /// code ....... }
Because if I press ESCAPE more times and it doesent work the program will crash.
Any suggestions?
P.S. My timer functions are like those above in miran's example. I set the timer to 0 before the loop. I used LOCKED_FUNCTION,LOCK_VARIABLE and END_OF_FUNCTION appropriately..
What you want to do is something like this:
1 | while (running ) { |
2 | |
3 | if (timer) { |
4 | int maxSkip = 4; |
5 | while(timer && maxSkip) { |
6 | // logic |
7 | --timer; |
8 | --maxSkip; |
9 | } |
10 | } else { |
11 | // good place to return some time to the system |
12 | // not sure what's currently the best way to do it, |
13 | // so check if this is still ok: |
14 | rest(0); |
15 | } |
16 | |
17 | running = ! key[KEY_ESC]; |
18 | } |
Normally, your code above should also work, unless your computer is very slow.
Don't put drawing code in the timed section! You only need to keep the logic rate down to 100 FPS (or whatever) but draw as many times as possible (or cap to logic framerate if you want). What happens with your code is that your computer isn't fast enough to draw 100 frames per second (remember, this is fullscreen software blitting), so the timer callback does ++timer faster than you can do --timer which means you never break out of the inner while. The solution is to add a check inside the inner while to see if the value of timer is some high unexpected number and if it is, reset it to 0 and break out of the while (effectively dropping frames). But unless you do some heavy processing in the timed section, this should never happen (except in situations you can't control, like some other program stealing the CPU or something).
In code this would look like this:
1 | while(!key[KEY_ESC]) |
2 | { |
3 | while(timer) |
4 | { |
5 | get_player_input(); |
6 | run_physics_engine(); |
7 | do_ai_processing(); |
8 | etc(); |
9 | |
10 | // Timer... |
11 | timer--; |
12 | |
13 | scene_needs_to_be_redrawn = true; |
14 | |
15 | if (timer > frame_drop_threshold) // like 20 or something |
16 | { |
17 | timer = 0; |
18 | break; |
19 | } |
20 | } |
21 | |
22 | if (scene_needs_to_be_redrawn) { |
23 | clear_bitmap(buffer); |
24 | draw_scene_to(buffer); |
25 | |
26 | // blast the buffer onto the visible screen |
27 | blit(buffer, screen, 0,0,0,0,SCREEN_W,SCREEN_H); |
28 | |
29 | scene_needs_to_be_redrawn = false; |
30 | } |
31 | } |
Now that's really almost all you need. All that's missing now is giving up the CPU when you can so you don't eat 100% and maybe handle the window close icon click and that's it as far as the main loop is concerned.
EDIT: Beaten by spellcaster. His code is a little better too...
EDIT: Beaten by spellcaster.
But I forgot to mention the that he needs to separate logic and drawing. So let's call it a draw
EDIT:
Could somebody reply in the transitions thread? I need to post the examples on how to use the fade code
Could somebody reply in the transitions thread? I need to post the examples on how to use the fade code
Done. But you can click "send to top" if it's been more than an hour and it will go to the top anyway. I think.
The problem was that my last post in that thread got too big. And I still wanted to post the examples. Since I can't double-post, I needed somebody to post in between
Now, the code works fine. But I have a problem. When I press Escape, the program exits. But then, I dont know if it exits like exits, or if it crashes. When I press ESC the program exits and then the "This application has encountered ... and must close..." message appears.
I have included all the source if someone can find the problem. Im still looking...
Thanks!
Your program crashes, that's what getting that dialog means. No one will go through your code for you though...
No, mogoče pa bi bil kdo dovolj nor...
Anyways im gonna keep looking. Thanks for the help with the timers miran & spellcaster!
Uuu, končn spet en Slowenc tuki gor!
EDIT:
Problem:
destroy_bitmap(title_image); unload_datafile(data);
Ne smeš uničit podatkov iz datafilea, ker unload_datafile() to naredi avtomatsko in potem sproščaš en in isti pointer dvakrat in potem se program sesuje.
English: You mustn't destroy data that was loaded from a datafile because unload_datafle() does that automatically. If you do that, you destroy the same pointer twice which crashes your program.
Ni kaj, bom še kr nekaj časa tu!
Kak me razjezijo take napake!! Pa tak se skrije! Hvala ti!
Thanks for the help miran, I wouldnt spot the bug whitout you!
I see you two have everything under control...
I think timer should be volatile int, not just int.
Shouldn't there be END_OF_FUNCTION() in there?
Also, LOCK_VARIABLE and LOCK_FUNCTION...
I don't know what the last two truly do, but the manual says to use them... That's usually a bad reason to do anything, though.
I have added END_OF_FUNCTION,LOCK_VARIABLE and LOCK_FUNCTION!
I don't know what the last two truly do, but the manual says to use them...
As far as I know, the LOCK_whatever calls are used because when you install the timers, you're creating a hardware interrupt. So, at a given interval, the hardware takes over and runs whatever functions/variables used in the install. I assume the LOCK_whatever calls help protect bad things from happening in this process (don't want other things fiddling with this portion of memory). So, really, it's just good practice.
I could be wrong though...
MacOS 9 and DOS are the only platforms that need the macros. The #defines are empty for all other platforms.
From allegro/platform/aldjgpp.h:
#define END_OF_FUNCTION(x) void x##_end(void) { } #define END_OF_STATIC_FUNCTION(x) static void x##_end(void) { } #define LOCK_DATA(d, s) _go32_dpmi_lock_data((void *)d, s) #define LOCK_CODE(c, s) _go32_dpmi_lock_code((void *)c, s) #define UNLOCK_DATA(d,s) _unlock_dpmi_data((void *)d, s) #define LOCK_VARIABLE(x) LOCK_DATA((void *)&x, sizeof(x)) #define LOCK_FUNCTION(x) LOCK_CODE((void *)x, (intptr_t)x##_end - (intptr_t)x)
I've implemented the interupt timing system and it works to keep the logic control. However, I get those nasty looking vertical refresh lines. Shouldn't the drawing also be slowed down? If not, do I have to use vsync() shudders?