Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?
Tutorial by Easykoder ®
www.easykoder.vot.pl
Biblioteki C++

Timery

[lekcja] Rozdział 9. Wywoływanie zadania co określony czas.
Po tak długiej przerwie wypada się przywitać... tak więc Witam Wszystkich, których cierpliwość przez ostatnie miesiące była wystawiona na ogromną próbę... ;p

Zaczniemy od historii... Odpalając czasami stare programy na nowych maszynach zauważamy często, że program działa za szybko (nie mówię tutaj oczywiście o drogich komercyjnych programach ;)... Chodzi tutaj o to, że jeśli piszemy jakąś gierkę na maszynie z prędkością zegara 500MHz, a później odpalamy ten sam program na maszynie 2000MHz, to wszystko co zaprogramowaliśmy w głównych pętach wykonuje się teraz kilkakrotnie szybciej. Tak więc wracając do naszego kursu... ostatnim razem pisaliśmy program, który wyświetlał postać którą mogliśmy poruszać... Jeśli posiadamy dwa kompy, które różnią się zasadniczo prędkością procesorów (taktowaniem zegarów), odpalmy nasz program na obu maszynach. I co zauważacie? Że na różnych kompach nasz program działa z różną prędkością.

Tak więc na tej lekcji nauczymy się posługiwać timerami, które służą właśnie do tego, aby ustawiać odpowiedni czas wykonywania różnych czynności w naszym programie, np. czas obiegu głównej pętli. Dzięki temu nasze gierki na różnych maszynach będą działać w zbliżonym tempie. Okej... bierzmy się do pracy. Kod tej lekcji oparty jest na kodzie poprzedniej, oczywiście pocięty komentarzami, nie powinno być problemu ze zrozumieniem całości.. :]

Zaczynamy jak zwykle, ładujemy bibliotekę Allegro:

C/C++
#include <allegro.h>

Tym razem potrzebujemy odpowiednich zmiennych i funkcji do naszego programu deklarujemy je jeszcze przed głównym programem:

volatile long speed = 0;
Przydomek volatile wyłącza stosowaną przez kompilator optymalizację. Używa się go wtedy, gdy dana zmienna jest często modyfikowana przez nieznaną kompilatorowi formę ( funkcję przerwania, itp.).

Dobra a teraz pora na naszą funkcję, która będzie zwiększała naszą zmienną speed o 1, chyba nie ma co wyjaśniać:

C/C++
void increment_speed()
{
    speed++;
}
END_OF_FUNCTION( increment_speed );

A teraz znowu coś nowego. Używamy specjalnych makr do tego, aby przypisać pamięć dla naszej zmiennej i funkcji. Są one przez cały czas wykorzystywane przez nasz program więc niech będą pod ręką ;)

C/C++
LOCK_VARIABLE( speed );
LOCK_FUNCTION( increment_speed );

A teraz to co już było:

C/C++
int main()
{
    allegro_init();
    install_keyboard();
    set_color_depth( 16 );
    set_gfx_mode( GFX_AUTODETECT, 640, 480, 0, 0 );

Tym razem dodajemy jeszcze obsługę timerów. W drugiej linii w procedurze BPS_TO_TIMER( czas ) jako czas podajemy ilość wykonywania operacji na sekundę. ( 100 to bezpieczna wartość lecz można śmiało kombinować ;) )

C/C++
install_timer();
install_int_ex( increment_speed, BPS_TO_TIMER( 100 ) );

I znowu to co już było, czyli tworzenie wskaźników na bitmapy, tworzenie bufora, wczytywanie bitmap itd.

C/C++
BITMAP * bufor = NULL;
BITMAP * ludek = NULL;

bufor = create_bitmap( 640, 480 );
if( !bufor )
{
    set_gfx_mode( GFX_TEXT, 0, 0, 0, 0 );
    allegro_message( "Nie mogę utworzyć bufora !" );
    allegro_exit();
    return 0;
}

ludek = load_bmp( "ludek.bmp", default_palette );
if( !ludek )
{
    set_gfx_mode( GFX_TEXT, 0, 0, 0, 0 );
    allegro_message( "nie mogę załadować obrazka Ludek !" );
    allegro_exit();
    return 0;
}

int ludek_x = 100, ludek_y = 100;

while( !key[ KEY_ESC ] )
{

No i tutaj najważniejsze, tworzymy nową pętlę która działa z prędkością jaką sobie ustawiliśmy na początku. Obejmujemy nią te procedury, które chcemy przyspieszyć bądź też spowolnić. W naszym przypadku jest to poruszanie ludzikiem.

C/C++
while( speed > 0 )
{
   
    if( key[ KEY_LEFT ] ) ludek_x--;
   
    if( key[ KEY_RIGHT ] ) ludek_x++;
   
    if( key[ KEY_UP ] ) ludek_y--;
   
    if( key[ KEY_DOWN ] ) ludek_y++;
   
    speed--;
}

clear_to_color( bufor, makecol( 150, 150, 150 ) );
masked_blit( ludek, bufor, 0, 0, ludek_x, ludek_y, ludek->w, ludek->h );
blit( bufor, screen, 0, 0, 0, 0, 640, 480 );
}

Na koniec zwalniamy miejsce zajęte przez naszą funkcję:

C/C++
remove_int( increment_speed );

destroy_bitmap( ludek );
destroy_bitmap( bufor );
allegro_exit();
return 0;
}
END_OF_MAIN();

No i to właściwie wszystko. Niektórych mogą przerażać te lekcje bo są długie... lecz większość kodu pochodzi z poprzednich lekcji. Zawsze pokazany jest cały kod, aby można było na szybko przetestować program kopiując zaznaczone fragmenty po kolei.

Tak więc przedstawię w skrócie jak wygląda używanie tych timerów:

1) Deklarujemy naszą zmienną i funkcję jeszcze przed funkcją główną main():

C/C++
volatile long speed = 0;
void increment_speed()
{
    speed++;
}
END_OF_FUNCTION( increment_speed );

2) Przydzielamy im stałe miejsce w pamięci:

C/C++
LOCK_VARIABLE( speed );
LOCK_FUNCTION( increment_speed );

3) Następnie w funkcji głównej instalujemy timer i ustawiamy pożądaną prędkość:

C/C++
install_timer();
install_int_ex( increment_speed, BPS_TO_TIMER( 100 ) );

4) W naszej pętli nieskończonej wstawiamy pętlę sterowaną przez nasz timer:

C/C++
while( speed > 0 )
{
   
    // Tu wstawiamy procedury, które mają być wykonywane z zadaną częstotliwością.
   
    speed--;
}

Jak więc widzimy korzystanie z timerów nie takie trudne, składa się raptem z 4 kroków...;) Wspomnieć jeszcze należy, że możemy w jednym programie używać kilku timerów. Jednak uważajmy na to, aby nie zapętlać jednego w drugim bo może dojść wtedy do dziwnych błędów czy zawieszenia programu.

Kody źródłowe programów

Zadania do tej i innych lekcji znajdziesz na naszym repozytorium.

Prawa autorskie

Serwis otrzymał zgodę od autora na publikację niniejszego materiału.
Poprzedni dokument Następny dokument
Podwójne buforowanie Animacja