Trochę więcej o sprite'ach
Ta lekcja będzie trochę dłuższa. Dowiesz się jak wycinać określone fragmenty powierzchni i wyświetlać je w odpowiednich miejscach. Do tego programu przygotuj sobie jakiś sprite, który będziesz chciał pociąć. Najlepiej gdyby miał takie wymiary, aby po pocięciu każdy fragment miał taki sam wymiar. Ja przygotowałem do lekcji bitmapę z liczbami 3, 2 i 1. Bitmapa ma wymiary 600x200 px, a więc po pocięciu na 3 części każda z nich będzie miała równe wymiary (tzn. 200x200 px). Naszym zadaniem będzie wycięcie tych liczb z bitmapy, uporządkowanie ich i wyświetlenie na ekranie. Liczby są ustawione malejąco, a my mamy za zadanie ułożyć je rosnąco. Najlepiej byłoby gdybyś skorzystał z mojej bitmapy dostarczonej z kursem (folder "Lekcja 4"). Zachęcam, abyś korzystał ze sprite'ów dostarczonych do kursu. Dzięki nim możesz lepiej nauczyć się programować w SDL-u, ponieważ są przygotowane tak, byś nie musiał zajmować się zbędnymi rzeczami. Oto kod:
#include <SDL.h>
SDL_Surface * ekran = NULL;
SDL_Surface * obraz = NULL;
SDL_Rect sprst[ 3 ];
SDL_Rect dprst[ 3 ];
int main( int argc, char * args[] )
{
SDL_Init( SDL_INIT_EVERYTHING );
ekran = SDL_SetVideoMode( 640, 480, 32, SDL_SWSURFACE );
obraz = SDL_LoadBMP( "liczby.bmp" );
sprst[ 0 ].x = 400;
sprst[ 0 ].y = 0;
sprst[ 0 ].w = 200;
sprst[ 0 ].h = 200;
sprst[ 1 ].x = 200;
sprst[ 1 ].y = 0;
sprst[ 1 ].w = 200;
sprst[ 1 ].h = 200;
sprst[ 2 ].x = 0;
sprst[ 2 ].y = 0;
sprst[ 2 ].w = 200;
sprst[ 2 ].h = 200;
dprst[ 0 ].x = 0;
dprst[ 0 ].y = 0;
dprst[ 1 ].x = 200;
dprst[ 1 ].y = 0;
dprst[ 2 ].x = 400;
dprst[ 2 ].y = 0;
SDL_BlitSurface( obraz, & sprst[ 0 ], ekran, & dprst[ 0 ] );
SDL_BlitSurface( obraz, & sprst[ 1 ], ekran, & dprst[ 1 ] );
SDL_BlitSurface( obraz, & sprst[ 2 ], ekran, & dprst[ 2 ] );
SDL_Flip( ekran );
SDL_Delay( 2000 );
SDL_Quit();
SDL_FreeSurface( obraz );
return 0;
}
Kod może wygląda strasznie, ale zaraz wszystko wyjaśnię. Na początku to co zawsze "podpięcie" SDL-a, potem deklaracja powierzchni, lecz pojawiają się nowe instrukcje:
SDL_Rect sprst[ 3 ];
SDL_Rect dprst[ 3 ];
Tutaj deklarujemy dwie tablice prostokątów.
Rect (skrót z ang. rectangle - prostokąt) to typ zmiennych prostokątów, które służą do operacji na powierzchniach. Liczba
3 w nawiasach kwadratowych na końcu mówi, że to
tablica trzech prostokątów. Prostokąty w SDL-u to fragmenty powierzchni o wymiarach, które ustalamy w programie na które możemy kopiować dowolne powierzchnie. Na razie nasze prostokąty zarezerwowały sobie tylko odpowiednią pamięć i mają wymiary 0x0 px, więc można powiedzieć, że nie istnieją. Jeden z nich nazwałem
sprst (source prostokąt - źródłowy prostokąt), a drugi (destination prostokąt " docelowy prostokąt). Wybacz za taki bigos angielsko - polski, ale postaram się więcej nie robić takich błędów -. Dalej mamy to, co już znasz - funkcja główna, inicjacja biblioteki, tworzenie okna, wczytanie bitmapy i:
sprst[ 0 ].x = 400;
sprst[ 0 ].y = 0;
sprst[ 0 ].w = 200;
sprst[ 0 ].h = 200;
sprst[ 1 ].x = 200;
sprst[ 1 ].y = 0;
sprst[ 1 ].w = 200;
sprst[ 1 ].h = 200;
sprst[ 2 ].x = 0;
sprst[ 2 ].y = 0;
sprst[ 2 ].w = 200;
sprst[ 2 ].h = 200;
dprst[ 0 ].x = 0;
dprst[ 0 ].y = 0;
dprst[ 1 ].x = 200;
dprst[ 1 ].y = 0;
dprst[ 2 ].x = 400;
dprst[ 2 ].y = 0;
Trochę tego dużo, ale to naprawdę proste. Spójrz na to:
sprst[ 0 ].x = 400;
sprst[ 0 ].y = 0;
sprst[ 0 ].w = 200;
sprst[ 0 ].h = 200;
Najpierw zajmujemy się pierwszym prostokątem z tablicy prostokątów źródłowych. Wcześniej wczytaliśmy do zmiennej obraz bitmapę z liczbami, teraz ustalamy jaki fragment ma być wycięty z tego sprite'a.
sprst[ 0 ].x = 400;
- tutaj ustalamy gdzie na bitmapie w poziomie ma się zacząć wycinany fragment. Ponieważ jest to struktura to za pomocą .
Kropki ustalamy przynależność
x do pierwszego prostokąta. Następnie nadajemy tej zmiennej (x) liczbę 400. Jednak program wie za mało. Aby wyciąć jakąś bitmapę należy podać współrzędne startowe prostokąta (x,y). Na razie program ma tylko x, więc czas na:
sprst[ 0 ].y = 0;
- tutaj podobnie jak wcześniej podajemy programowi miejsce, z którego ma wyciąć fragment, tyle że w pionie. My chcemy wyciąć cały obszar bitmapy w pionie, więc ustalamy, że wycinanie zacznie się od pierwszego (0) piksela. Teraz program wie, że ma wyciąć fragment, który zaczyna się w punkcie o współrzędnych (400,0) bitmapy z liczbami. Zaraz, program wie skąd ma zacząć, ale nie wie jaki fragment musi wyciąć. Pisałem wcześniej, że bitmapa z liczbami ma wymiary 600x200 px i jest 3 liczby. Wychodzi na to, że na każdą liczbę przypada 200x200 px. Oto instrukcje, które "mówią" programowi jaki to ma być fragment:
sprst[ 0 ].w = 200;
sprst[ 0 ].h = 200;
Widzisz, że doszła nowa zmienna w. Jest to skrót od angielskiego słowa
width, które po polsku znaczy
szerokość. Szerokość ta dotyczy wycinanego fragmentu powierzchni. Ustaliliśmy wcześniej, że każdy wycięty fragment bitmapy ma szerokość 200 px, a więc podajemy tu liczbę 200.
sprst[ 0 ].h = 200;
- w tym miejscu ustalamy ile ma mieć wycięty fragment w pionie. Litera h to skrót od angielskiego wyrazu
height - wysokość. Analogicznie do szerokości fragmentu sprite'a wysokość również ma
200 px.
Dalej mamy takie funkcje:
sprst[ 1 ].x = 200;
sprst[ 1 ].y = 0;
sprst[ 1 ].w = 200;
sprst[ 1 ].h = 200;
sprst[ 2 ].x = 0;
sprst[ 2 ].y = 0;
sprst[ 2 ].w = 200;
sprst[ 2 ].h = 200;
Jest to to samo, co wcześniej tylko tutaj ustalamy dane dotyczące dwóch pozostałych fragmentów wyciętych z bitmapy. Różnią się one tylko miejscem wycięcia fragmentu. Jeśli to dla Ciebie nadal jest nie jasne to spójrz na ten obrazek:
Kolory zielony, niebieski i pomarańczowy oznaczają prostokąty (zmienne typu SDL_Rect). Każdy z prostokątów ma wymiary 200x200 pikseli. Za pomocą zmiennych x oraz y, które należą do każdego prostokąta (np. sprst[0].x lub sprst[2].y) "wskazujemy" każdemu prostokątowi gdzie na bitmapie źródłowej ma się zaczynać. Czarne kropki w rogach prostokątów to współrzędne punktów, w których te prostokąty się zaczynają. Teraz wszystko powinno być jasne.
Kolejna porcja kodu do objaśnienia:
dprst[ 0 ].x = 0;
dprst[ 0 ].y = 0;
dprst[ 1 ].x = 200;
dprst[ 1 ].y = 0;
dprst[ 2 ].x = 400;
dprst[ 2 ].y = 0;
Trochę się zmieniło. Jak zauważyłeś tutaj zmieniamy dane innych 3 prostokątów, które definiowaliśmy na początku programu:
SDL_Rect dprst[3];
Podobnie jak wcześniej nazwałem je
dprst, co po rozwinięciu oznacza destination prostokąt - docelowy prostokąt. Tutaj ustalamy tylko w jakim miejscu ma być wyświetlony dany prostokąt. Np. te dane mówią:
dprst[ 1 ].x = 200;
dprst[ 1 ].y = 0;
Prostokąt 2 ma być umieszczony na ekranie w miejscu, którego współrzędne wynoszą 400 i 0. Nie ustalamy jaki ma być wymiar prostokąta (domyślnym ustawieniem wielkości prostokąta jest 0 pikseli szerokości i 0 wysokości), ponieważ ustaliliśmy wcześniej (
sprst[]), że każdy z prostokątów ma pobierać z obrazka wycinek o wymiarach
200x200.
SDL_BlitSurface( obraz, & sprst[ 0 ], ekran, & dprst[ 0 ] );
SDL_BlitSurface( obraz, & sprst[ 1 ], ekran, & dprst[ 1 ] );
SDL_BlitSurface( obraz, & sprst[ 2 ], ekran, & dprst[ 2 ] );
Funkcja, którą już znasz. Ta funkcja zajmuje się kopiowaniem powierzchni. Kopiujemy 3 prostokąty. Różnicą między tym, a kopiowaniem z poprzedniego programu jest lista argumentów.
1. argument - powierzchnia, z której chcemy coś skopiować. Tutaj podany jest prostokąt obraz, w którym jak wiesz przechowywana jest bitmapa z liczbami.
2. argument - dane dotyczące wycinka, który kopiujemy. Wcześniej zdefiniowaliśmy prostokąty
sprst, a następnie ustalaliśmy dane wycinków powierzchni. Nie piszemy tutaj wprost nazwy źródłowego prostokąta. Przed nazwą musi się znajdować znaczek &, który jest referencją do powierzchni. Funkcja przechodzi przez referencję do powierzchni i pobiera dane o określonym wycinku. Dalej, po zmiennej w nawiasach kwadratowych podaliśmy numer powierzchni, gdyż wcześniej zdefiniowaliśmy tablicę prostokątów. Gdy definiujesz jeden prostokąt, nie piszesz nawiasów kwadratowych, ani liczby.
3. argument - tak jak w argumencie 1, z tym że tu podajemy, gdzie chcemy skopiować bitmapę, czyli podajemy powierzchnię docelową.
4. argument - tak jak argument 2, lecz tutaj przekazujemy funkcji dane, gdzie ma być skopiowany wycinek bitmapy.
Na koniec program odświeża ekran, czeka
2 sekundy, kończy pracę SDL-a i usuwa bitmapę.