Zanim przystąpimy do rysowania pierwszych obiektów na scenie musimy przerobić jeszcze kilka ważnych rzeczy, a jedną z nich są zdarzenia
(ang. events). Zdarzenia odpowiadają bowiem za wszelką interakcję z oknem - począwszy od obsługi przycisku zamykającego okno, a skończywszy na obsłudze klawiatury, myszy czy też joysticka.
Organizacja obsługi zdarzeń w SFML
Zdarzenia w bibliotece SFML są magazynowane przez okno. Każde okno posiada swój własny magazyn. Magazyn zdarzeń jest w rzeczywistości stosem do którego trafiają aktualne zdarzenia. Zdarzenia oczekujące należy systematycznie odczytywać - w przeciwnym wypadku możesz doprowadzić do sytuacji w której zdarzenia będą obsługiwane z dużym opóźnieniem bądź w skrajnych przypadkach nie zostaną obsłużone wcale.
W celu zapewnienia prawidłowej obsługi zdarzeń twórcy SFML zalecają odczytywać wszystkie oczekujące zdarzenia przy każdym obiegu pętli głównej programu. Jak to zrobić? Zaraz się tego dowiesz :)
Odczytywanie oczekujących zdarzeń
W poprzednim rozdziale utworzyliśmy obiekt okna typu
Window. Klasa
Window biblioteki SFML posiada metodę
GetEvent. Metoda ta przyjmuje jako argument referencję na zmienną typu
sf::Event, która w rzeczywistości jest strukturą. W przypadku gdy uda się pobrać zdarzenie z kontenera to metoda
GetEvent zwróci prawdę (wartość
true), a zmienna typu
sf::Event przekazana poprzez argument zostanie wypełniona informacjami o odczytanym zdarzeniu. Jeżeli w magazynie zdarzeń nie będzie więcej zdarzeń do odczytania - metoda
GetEvent zwróci fałsz, tj. wartość
false.
Skoro wiemy już jak sprawy się mają w teorii to zobaczmy teraz jak będzie to wyglądało w praktyce:
sf::Event zdarzenie;
if( oknoAplikacji.GetEvent( zdarzenie ) )
{
}
Powyższy zapis odczyta tylko jeden komunikat z magazynu zdarzeń (pod warunkiem, że zdarzenie będzie istniało). Nam zależeć będzie jednak na odczytaniu wszystkich zdarzeń oczekujących w magazynie na obsłużenie, więc instrukcję warunkową
if zastąpimy pętlą
while:
sf::Event zdarzenie;
while( oknoAplikacji.GetEvent( zdarzenie ) )
{
}
Tak jak już wcześniej pisałem pętla odczytująca zdarzenia powinna znajdować się w pętli głównej programu - w praktyce więc Twój kod powinien być zbudowany mniej więcej tak:
#include <SFML/Window.hpp>
int main()
{
sf::Window oknoAplikacji( sf::VideoMode( 800, 600, 32 ), "Kurs SFML - http://cpp0x.pl" );
while( oknoAplikacji.IsOpened() )
{
sf::Event zdarzenie;
while( oknoAplikacji.GetEvent( zdarzenie ) )
{
}
oknoAplikacji.Display();
}
return 0;
}
Obsługa zdarzeń
Skoro wiemy już jak odczytywać zdarzenia to dobrze by było umieć je jeszcze obsłużyć. Zanim to jednak nastąpi zapoznajmy się najpierw z typami zdarzeń, jakie mamy do dyspozycji. Wszystkie typy zdarzeń, które możemy obsłużyć zostały umieszczone w strukturze
sf::Events.
Typ otrzymanego zdarzenia możemy odczytać z pola
Type należącego do struktury
sf::Event. Dla niektórych zdarzeń otrzymanych przez metodę
GetEvent ustawiane są dodatkowo niektóre pola struktury
sf::Event, które umożliwiają odczytanie dodatkowych informacji na temat zdarzenia jakie miało miejsce. Poniższa tabela zawiera informacje o tym jakie dodatkowe pola struktury
sf::Event są ustawione w zależności od zdarzenia:
Obsługa zdarzenia zamykającego okno
Skoro mamy już ogromną wiedzę teoretyczną na temat zdarzeń za sobą, zajmijmy się teraz nimi od strony praktycznej. Pierwszym zdarzeniem, które zostanie omówione to obsługa przycisku zamykającego okno. W Bibliotece SFML wygląda to następująco:
if( zdarzenie.Type == sf::Event::Closed )
{
}
Samo przyjście zdarzenia nie powoduje jednak zamknięcia okna - jest to tylko informacja, że użytkownik chciał zamknąć okno. Dzięki temu mamy możliwość zapisania stanu gry przed zamknięciem aplikacji, czy też wyświetlenie dodatkowego komunikatu potwierdzającego zamknięcie aplikacji.
Zamykanie okna
Skoro już wiemy jak podpiąć się pod zdarzenie zamknięcia okna, sprawmy teraz by się ono zamknęło. Do tego celu wykorzystać musimy metodę
Close, która należy do klasy
Window. Kompletny kod zamykający okno może wyglądać tak:
if( zdarzenie.Type == sf::Event::Closed )
{
oknoAplikacji.Close();
}
Obsługa klawiatury
Zdarzenia klawiatury obsługuje się analogicznie do zdarzenia zamknięcia okna. Najpierw sprawdzamy czy zdarzenie jest typu
sf::Event::KeyPressed bądź
sf::Event::KeyReleased w zależności od tego jakie nas interesuje. Struktura
Event posiada pole o nazwie
Key z którego możemy odczytać kod klawisza, który został wciśnięty oraz jaki był stan klawiszy funkcyjnych (ALT, CTRL i SHIFT) w chwili gdy zaszło to zdarzenie. Kody klawiszy są zdefiniowane przez bibliotekę SFML i ich definicje są umieszczone w przestrzeni nazw
sf::Key w pliku
Events.hpp. Dla małych liter jak również cyfr - kod klawisza jest taki sam jak dla kodu ASCII. Oznacza to, że zapis
'p' jest równoważny zapisowi
sf::Key::P, a zapis
'6' jest równoważny zapisowi
sf::Key::Num6. Specjalnej filozofii w korzystaniu ze zdarzeń klawiatury nie ma, więc przejdźmy teraz do przykładu:
if( zdarzenie.Type == sf::Event::KeyPressed && zdarzenie.Key.Code == sf::Key::Escape )
{
oknoAplikacji.Close();
}
Obsługa myszy
Jak zapewne zauważyłeś obsługa zdarzeń w bibliotece SFML nie wymaga specjalnie dużych umiejętności programowania, jak również wielu linii kodu. Mysz jest równie prosta w obsłudze co klawiatura. Tabela, która została przedstawiona w niniejszym rozdziale zawiera pola struktury, które są modyfikowane dla poszczególnych zdarzeń - w tym myszy. Przykładowo zdarzenie
MouseButtonPressed posiada wypełnione pole
MouseButton.Button dla struktury typu
Events. Mysz tak samo jak klawiatura posiada definicje przycisków. Definicje te są następujące:
Jeżeli będziemy chcieli aby okno SFML zamykało się w momencie gdy zostanie wciśnięty środkowy klawisz, wystarczy napisać następujący kod:
if( zdarzenie.Type == sf::Event::MouseButtonPressed && zdarzenie.MouseButton.Button == sf::Mouse::Middle )
oknoAplikacji.Close();
Pozostałe zdarzenia myszy obsługuje się analogicznie - przypominam, że szczegółowe informacje o wszystkich zdarzeniach zostały zawarte w jednej z tabel niniejszego rozdziału.
Przykład
Podsumujmy teraz całą wiedzę wyniesioną z niniejszego rozdziału jednym, krótkim kodem programu:
#include <SFML/Window.hpp>
int main()
{
sf::Window oknoAplikacji( sf::VideoMode( 800, 600, 32 ), "Kurs SFML - http://cpp0x.pl" );
while( oknoAplikacji.IsOpened() )
{
sf::Event zdarzenie;
while( oknoAplikacji.GetEvent( zdarzenie ) )
{
if( zdarzenie.Type == sf::Event::Closed )
oknoAplikacji.Close();
if( zdarzenie.Type == sf::Event::KeyPressed && zdarzenie.Key.Code == sf::Key::Escape )
oknoAplikacji.Close();
if( zdarzenie.Type == sf::Event::MouseButtonPressed && zdarzenie.MouseButton.Button == sf::Mouse::Middle )
oknoAplikacji.Close();
}
oknoAplikacji.Display();
}
return 0;
}
Obsługa innych zdarzeń
Inne zdarzenia, które są dostępne w bibliotece SFML obsługuje się analogicznie do tych, które zostały już omówione. Nie wydaje mi się jednak aby przytaczanie ich obszernego opisu wraz z przykładami miało na chwilę obecną większy sens dlatego też pozwolę sobie w tym miejscu zakończyć niniejszy rozdział by móc omówić kolejne interesujące aspekty biblioteki SFML :)