Wprowadzenie
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.
Jak jest zorganizowana obsługa zdarzeń w SFML
Zdarzenia w bibliotece
SFML 2.0 są magazynowane przez okno. Każde okno posiada swój własny magazyn. Magazyn zdarzeń jest w rzeczywistości kolejką do której 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
sf::Window. Klasa
sf::Window biblioteki SFML posiada metodę
pollEvent. Metoda ta przyjmuje jako argument referencję na zmienną typu
sf::Event, która w rzeczywistości jest klasą. W przypadku gdy uda się pobrać zdarzenie z kontenera to metoda
pollEvent 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
pollEvent 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.pollEvent( 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.pollEvent( 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 2.0 - http://cpp0x.pl" );
while( oknoAplikacji.isOpen() )
{
sf::Event zdarzenie;
while( oknoAplikacji.pollEvent( 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 klasie
sf::Event.
Typ otrzymanego zdarzenia możemy odczytać z pola
type należącego do klasy
sf::Event. Dla niektórych zdarzeń otrzymanych przez metodę
pollEvent ustawiane są dodatkowo niektóre pola klasy
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 klasy
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
sf::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. Klasa
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 klasie
sf::Keyboard w pliku
Keyboard.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::Keyboard::P, a zapis
'6' jest równoważny zapisowi
sf::Keyboard::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::Keyboard::Escape )
{
oknoAplikacji.close();
}
Obsługa myszy
Jak zapewne zauważyłeś obsługa zdarzeń w bibliotece
SFML 2.0 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 klasy, które są modyfikowane dla poszczególnych zdarzeń - w tym myszy. Przykładowo zdarzenie
MouseButtonPressed wypełnia pole
mouseButton.button dla klasy typu
sf::Event. 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 2.0 - http://cpp0x.pl" );
while( oknoAplikacji.isOpen() )
{
sf::Event zdarzenie;
while( oknoAplikacji.pollEvent( zdarzenie ) )
{
if( zdarzenie.type == sf::Event::Closed )
oknoAplikacji.close();
if( zdarzenie.type == sf::Event::KeyPressed && zdarzenie.key.code == sf::Keyboard::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 2.0 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 :)