Zastanówmy się nad tym czego nam jeszcze do szczęścia brakuje? Ekran już nie miga, program działa w wyznaczonym tempie, nasz ludek porusza się... zaraz!... właśnie, przecież nasz ludek wcale się nie porusza! On się tylko przemieszcza, a to wielka różnica! Chcąc stworzyć jakąś grę, będziemy musieli wprowadzić jakieś ładne animacje do naszego projektu, nie będziemy przecież latać nieruchomym ludzikiem!
Z racji tego, że w Allegro wszystko jest proste, domyślacie się pewnie, że z animacją również nie będzie problemu? I oczywiście macie rację, bo czym jest animacja jeśli nie seryjnym wyświetlaniem odpowiednich obrazków w odpowiednim czasie? A skoro potrafimy już wyświetlać obrazki, to w czym problem? Stwórzmy więc program, który wyświetli jakąś animację.
Do naszego programu będziemy potrzebowali, kilku obrazków. U mnie są to kolejne klatki ludzika, który porusza swoimi rękoma, czyli zwykła animacja machania rękoma. Pamiętajmy o tym, że jeśli chcemy otrzymać dobrą animację powinna być płynna, czyli składać się z większej ilości klatek, na których widać jak najmniejsze przemieszczenia danego elementu. Mi nie zależy na jakości bo jest to program demonstracyjny... ;p tak więc u mnie zwykłe machnięcie rękoma znajduje się na 4 klatkach.
Przystąpmy więc do pracy. Jak zwykle pocięty kodzik wraz z potrzebnymi objaśnieniami. Na początku standard, czyli inicjowanie biblioteki, timera, ustawianie trybu graficznego.
#include <allegro.h>
volatile long speed = 0;
void increment_speed()
{
speed++;
}
END_OF_FUNCTION( increment_speed );
LOCK_VARIABLE( speed );
LOCK_FUNCTION( increment_speed );
int main()
{
allegro_init();
install_keyboard();
set_color_depth( 16 );
set_gfx_mode( GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0 );
install_timer();
install_int_ex( increment_speed, BPS_TO_TIMER( 80 ) );
Teraz pora na zadeklarowanie BITMAP pod wszystkie klatki naszej animacji, no i oczywiście bufora.
BITMAP * bufor = NULL;
BITMAP * ludek0 = NULL;
BITMAP * ludek1 = NULL;
BITMAP * ludek2 = NULL;
BITMAP * ludek3 = NULL;
Tworzymy bufor i ładujemy grafiki do naszych zmiennych. Nie sprawdzamy czy zostały utworzone, oszczędzając miejsce ;-p...
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;
}
ludek0 = load_bmp( "bobek00.bmp", default_palette );
ludek1 = load_bmp( "bobek01.bmp", default_palette );
ludek2 = load_bmp( "bobek02.bmp", default_palette );
ludek3 = load_bmp( "bobek03.bmp", default_palette );
Następnie deklarujemy nasze zmienne takie jak: pozycja ludzika na ekranie oraz nową zmienną frame, dzięki której będziemy sprawnie operować wyświetlaniem odpowiedniej klatki.
int ludek_x = 100, ludek_y = 100;
int frame = 0;
while( !key[ KEY_ESC ] )
{
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--;
frame++;
if( frame > 80 ) frame = 0;
}
Jak pamiętamy ustawiliśmy nasz timer na
80 cykli w ciągu sekundy ( BPS_TO_TIMER(80) ), więc w ciągu
sekundy nasza zmienna
frame osiągnie wartość
80 i potem znowu spadnie
do zera. Nasza animacja składa się z
4 klatek, więc podzielimy teraz czas animacji przez ilość klatek, co daje nam
20. Więc jeśli chcemy, aby nasza animacja trwała sekundę, każdej z klatek przydzielamy odpowiedni (po 20) przedział framesów. Następnie wyświetlamy odpowiednią klatkę animacji.
clear_to_color( bufor, makecol( 150, 150, 150 ) );
if( frame < 20 ) { draw_sprite( bufor, ludek0, ludek_x, ludek_y ); }
else if( frame >= 20 && frame < 40 ) { draw_sprite( bufor, ludek1, ludek_x, ludek_y ); }
else if( frame >= 40 && frame < 60 ) { draw_sprite( bufor, ludek2, ludek_x, ludek_y ); }
else if( frame >= 60 && frame < 80 ) { draw_sprite( bufor, ludek3, ludek_x, ludek_y ); }
blit( bufor, screen, 0, 0, 0, 0, 640, 480 );
}
Na koniec nie pozostaje nam nic innego jak posprzątać po naszym programie. Usuwamy więc nasz timer i wszystkie bitmapy.
remove_int( increment_speed );
destroy_bitmap( ludek0 );
destroy_bitmap( ludek1 );
destroy_bitmap( ludek2 );
destroy_bitmap( ludek3 );
destroy_bitmap( bufor );
allegro_exit();
return 0;
}
END_OF_MAIN();
Tak naprawdę omówione wyżej wyświetlanie animacji, nie jest zbyt fachowe, co można zauważyć na pierwszy rzut oka ;-p Celem tej lekcji było przedstawienie ogólnej zasady animacji, która polega po prostu na wyświetleniu w odpowiednim czasie i miejscu odpowiedniej grafiki. I jak się okazało nie jest to takie trudne.
W powyższym przykładzie użyliśmy procedury
draw_sprite(bufor, ludek2, ludek_x, ludek_y); której argumentami są: bitmapa, na której chcemy wyświetlić nasz obrazek; bitmapa którą chcemy wyświetlić; pozycja X obrazka; pozycja Y obrazka. Powyższa procedura jest jednak niezbyt użyteczna, o czym przekonasz się czytając różne przykłady z tej strony.
Tworząc bitmapy na potrzeby gry, nie będziemy ładować każdej z klatek do osobnej struktury BITMAP. Nie będziemy umieszczać ich nawet w tablicach. Gdyż wszystkie klatki animacji skleimy w jedną wielką bitmapę, z której będziemy pobierać interesujący nas fragment, za pomocą procedury blit lub masked_blit. Szybko zauważycie przewagę tego sposobu nad zaprezentowanym wyżej. Ale o tym kiedy indziej.
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.