Using timers
Vanneto

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!

miran

Almost all you need to know:

1int timer;
2void timer_f() {
3 ++timer;
4}
5 
6int 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.

spellcaster

Just make sure to set "timer" to 0 before entering the loop shown above.

Vanneto

Can you manage how many times a second should the loop go?

EDIT: Yeah im stupid. Found that out! Thanks!

spellcaster

Yes.
Try clicking the function name in the source code below:

install_int_ex(timer_f, BPS_TO_TIMER(100));

Vanneto

What if I have such code:

        while(!key[KEY_ESC])
        {
            while(timer)
            {
                // Print and Clear the buffer so no 'drawing' occurs
                blit(buffer, screen, 0,0,0,0,SCREEN_W,SCREEN_H);
                clear_bitmap(buffer);

                // Timer...
                timer--;
            }
        }

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..

spellcaster

What you want to do is something like this:

1while (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.

miran

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:

1while(!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... :-X

spellcaster
Quote:

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 ;)

miran
Quote:

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.

spellcaster

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 ;)

Vanneto

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!

miran

Your program crashes, that's what getting that dialog means. No one will go through your code for you though...

Vanneto

No, mogoče pa bi bil kdo dovolj nor... :D

Anyways im gonna keep looking. Thanks for the help with the timers miran & spellcaster! :)

miran

:o:o:o Uuu, končn spet en Slowenc tuki gor! :o:o:o

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.

Vanneto

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! :)

Kibiz0r

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.

Vanneto

I have added END_OF_FUNCTION,LOCK_VARIABLE and LOCK_FUNCTION!

Onewing
Quote:

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...

Matthew Leverton

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)

aadfo824

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?

Thread #591494. Printed from Allegro.cc