Kategoria

SFML – kurs podstawowy

Pozycja, rotacja, skalowanie: przekształcanie obiektów

Przekształcenia


Wszystkie obiekty, które można przekształcać (transform) dziedziczą po klasie sf::Transformable, to ona pozwala im na te wszystkie czynności.

Ta klasa ma 4 właściwości: pozycję (position), rotację(rotation), skalę (scale) oraz origin. Ich użycie jest bardzo proste i intuicyjne.

Pozycja

Pozycja, to po prostu pozycja obiektu na scenie 2D, każdy kto miał do czynienia z układem współrzędnych wie o co chodzi 🙂

Standardowo obiekty porusza się względem punktu, który leży w lewym górnym rogu obiektu, można to zmienić, ale o tym później.

 

Rotacja

Jest to po prostu obracanie obiektów, jest ona definiowana w stopniach zgodnie z ruchem wskazówek zegara.

Zauważ że pobierana rotacja zawsze zawiera się w przedziale [0,360]. Tak jak w przypadku pozycji, tak samo rotacja jest dokonywana względem standardowo lewego górnego rogu.

 

Skala

Czyli faktor, który wskazuje zmianę rozmiaru obiektu. Jeżeli jest większy niż 1 to wiem że obiekt został powiększony, mniejszy od 1 pokazuje że obiekt został pomniejszony, a równy 1 mówi że obiekt jest nieskalowany.

 

Origin

Jest to punkt, wg którego wykonywane są operacje typu: przesuwanie, obracanie obiekt, itp. Standardowo jest on ustawiany na lewy górny róg obiektu. Jeżeli chcesz go zmienić to nie ma problemu, można w bardzo łatwy sposób go zmienić.

Zauważ, że po zmianie punktu origin, zmianie także ulega wizualna pozycja obiektu.

 

Przekształcanie (transformowanie) własnej klasy


sf::Transfromable możesz dziedziczyć, dzięki czemu możesz uzyskać jej właściwości w twojej klasie.

Aby użyć ostatecznie właściwości Transformable musisz użyć getTransform (zazwyczaj podczas wykonywania draw), poniżej nieco bardziej to wyjaśnię.

Jeżeli nie chcesz korzystać z całej funkcjonalności tej klasy, to możesz użyć jej po prostu jako członka swojej klasy, a funkcje możesz albo pozostawić w obecnej formie, albo możesz napisać własne przez zasłonięcie tych z tej klasy.

 

Rozszerzanie możliwości Transformable


Klasa Transformable jest łatwa w użyciu, ale jednocześnie bardzo ograniczona. Może się zdarzyć, że będziesz potrzebował więcej możliwości, typu łączenie kilku przekształceń w  jedno itp. Jeżeli tak jest w twoim przypadku, to jest nisko poziomowa klasa sf::Transform, która jest 3×3 matrix’em, dzięki czemu może być reprezentowana przez przekształcenia w świecie 2D.

Jest wiele sposobów na użycie sf::Transform:

  • przez użycie predefiniowanych funkcji dla najczęściej spotykanych transformacji (translacja, skala, rotacja)
  • przez połączenie dwóch transformacji
  • przez bezpośrednie określenie 9 elementów.

Kilka przykładów:

Możesz oczywiście wszystkie transformacje zawrzeć w jednej:

Aby wykorzystać te transformacje musisz:

Forma powyżej jest krótszą wersją:

 

Bounding boxes


Po wykonaniu  transformacji być może chciałbyś wykonać jakieś obliczenia na nich, np do sprawdzenia kolizji.

Obiekty w SFML mogą podać ci tzw bounding box, czyli najmniejszy prostokąt potrzebny do zamknięcia obiektu w prostpkącie.

Bounding box może być przydatny w sprawdzaniu kolizji i można go pobrać bardzo szybko.

Funkcja getGlobalBounds pobiera bounding box z uwzględnieniem transformacji (rotacja itp), getLocalBounds nie bierze tych zmian pod uwagę.

Jednak może się okazać, że ten rodzaj kolizji nie będzie dla ciebie odpowiednio dokładny, możliwe że przyda ci się to co przekazałem w moim kursie Piszemy grę w SFML w lekcji o kolizjach.

 

Hierarchia obiektów


Dzięki temu co napisaliśmy wcześniej możemy w łatwy sposób napisać klasę, która będzie decydowała o hierarchii obiektów, gdzie potomkowie danych obiektów (children) będą transformowane zgodnie z ich rodzicami (parents). Wszystko co musisz zrobić to przekazanie połączenia przekształcenia z rodzica na dzieci podczas ich rysowania.

Oryginalny artykuł

Projektowanie własnych „jednostek” przy pomocy VertexArray

Wstęp


Jeżeli poszukujesz klasy która pozwoli ci w nieco bardziej rozbudowany sposób urozmaicić kształty w SFML lub chcesz stworzyć swoje własne figury to ten tutorial jest dla ciebie.

Zadajmy sobie pytanie czym jest Vertex Array? Z angielskiego wiemy, że to po prostu tablica wierzchołków. Vertex jest najmniejszą dostępną jednostką jaką możemy manipulować. Posiada pozycję (x,y lub x,y,z), a także kolor i parę współrzędnych tekstury.

Wierzchołki pojedynczo nie robią wiele, dlatego łączy się je w prymitywy: 1 wierzchołek tworzy punkt, 2 tworzą linię, 3 – trójkąt, 4 -czworokąt. Gdy połączysz 1 lub więcej wierzchołków razem otrzymasz geometryczną reprezentację figury.

 

VertexArray


Na początku przyjrzyjmy się strukturze sf::Vertex, która przechowuje 3 publiczne elementy: pozycję (position), kolor (color), teksturę (texCoords). Przy tworzeniu musisz się zdecydować czy wybierasz użycie koloru, czy tekstury. Możesz te elementy uzupełnić poprzez wywołanie je jak w każdej standardowej klasie:

lub możesz uzupełnić je używając konstruktora:

Teraz sprawmy aby wierzchołki utworzyły nam typ prymitywny. Pamiętamy przy tym, że aby stworzyć typ prymitywny musimy użyć kilku wierzchołków, czyli potrzebujemy na nie tablicy sf::VertexArray. Jest to typ danych podobnych do std::vector i jego użycie jest analogiczne.

Nasz trójkąt jest już gotowy, jak zauważyłeś użyliśmy 3 różnych kolorów, narysujmy to i zobaczmy jak to się prezentuje.

W ten sposób możesz tworzyć m.in. gradienty.

Zauważ, że nie musisz korzystać z VertexArray, możesz równie dobrze posłużyć się wcześniej wspomnianym std::vector, wtedy rysowanie wygląda w trochę inny sposób.

Możesz też użyć tradycyjnych tablic:

 

Rodzaje prymitywów


Najwyższa pora to poznania rodzajów prymitywów jakie możesz spotkać w SFML.

sf::Points

Jest to zbiór niepołączonych ze sobą punktów, punkty nie mają swojej grubości, zawsze są o wielkości 1 piksela, niezależnie od przekształceń i view (klasa w SFML).

sf::Lines

Zbiór niepołączonych ze sobą linii, są zawsze grubości 1 piksela, niezależnie od przekształceń i użycia view.

sf::LinesStrip

Zbiór połączonych ze sobą linii, ostatni wierzchołek jest łączony z pierwszym wierzchołkiem i tworzy figurę zamkniętą.

sf::Triangles

Zbiór niepołączonych ze sobą trójkątów.

sf::TrianglesStrip

Zbiór połączonych ze sobą trójkątów, każdy trójkąt udostępnia 2 ostatnie wierzchołki następnemu trójkątowi.

sf::TrianglesFan

Zbiór połączonych trójkątów połączonych z 1 centralnym punktem. Pierwszy wierzchołek jest centralnym punktem, każdy nowy vertex tworzy nowy trójkąt, używając środek i poprzedni vertex.

sf::Quads

Zbiór niepołączonych ze sobą kwadratów. Każde z 4 wierzchołków muszą być zdefiniowane w kolejności zgodnej lub przeciwnej do wskazówek zegara.

 

Nadawanie tekstur (texturing)


Tak jak reszta obiektów w SFML tak i Vertex może być teksturowany. Aby to zrobić musisz użyć texCoords, ta zmienna definiuje który piksel tekstury ma być mapowany do Vertex‚a.

Współrzędne tekstury są w pikselach i nie są normalizowane (nie mają wartości pomiędzy 0, a 1), tak jak osoby piszące w openGL mogłyby się spodziewać.

VertexArray to nisko poziomowy typ, a więc nie przechowują one tekstury. Aby narysować je z teksturą należy ją dostarczyć bezpośrednio do funkcji draw.

To jest ta prostsza wersja, jednak gdybyś potrzebował użyć render states (przekształceń lub blend mode) to możesz użyć rozszerzonej wersji używającej sf::RenderStates.

 

Przekształcenia VertexArray


VertexArray ulega przekształceniom w podobny sposób jak w przypadku teksturowania.

Lub:

Aby wiedzieć o samej klasie sf::Tranform przeczytaj kurs o Przekształceniach.

 

Tworzenie „SFML-like” jednostek


Jeżeli twoim zdaniem pokazane wcześniej klasy są dla ciebie niewystarczające to za pomocą sf::Drawable oraz sf::Transformable. Te dwie klasy są bazą dla klas takich jak sf::Sprite, sf::Text, czy sf::Shape.

sf::Drawable to interfejs, ta funkcja jedynie deklaruje pustą wirtualną funkcję draw, której dziedziczenie pozwoli ci użyć funkcji draw to narysowania obiektów.

Zauważ że funkcja draw wykonana przez ciebie jest uruchamiana wewnątrz window.draw. W ten sposób kod wygląda przejrzyściej i ładniej.

Kolejną klasą jest sf::Transformable, która nie ma funkcji wirtualnych. Dziedziczenie po niej daje ci automatycznie standardowe dla tej klasy metody (obracanie, ustawianie pozycji, itd.).

Standardowa klasa graficzna w SFML wygląda w ten sposób:

Możesz także korzystać z wbudowanych w SFML klas:

 

Przykład: mapa kafelkowa


Wykorzystajmy to co widzieliśmy powyżej, cała mapa będzie zawarta w pojedynczym VertexArray, dzięki temu będzie rysowana bardzo szybko. Zauważ, że w tym przykładzie pobieramy kafelki zakładając, że wszystkie tektury kafelków są w 1 pliku (tileset).

A także użycie tego przez program:

 

Przykład: system cząsteczek


Drugim przykładem będzie system cząsteczek, będzie to o tyle prostsze, że nie będziemy musieli używać tekstur. Jeżeli chcesz wiedzieć na jakiej zasadzie działają systemy cząsteczek odsyłam cię do strony Nature of Code.

Oraz sposób użycia:

Oryginalny artykuł

Tekst i czcionki

Wczytywanie czcionek


Zanim będziesz mógł wyświetlić tekst, będziesz musiał ustawić mu jakąś czcionkę. Czcionki są zawarte w klasie sf::Font (hermetyzowane) i zawierają 3 główne cechy: wczytywanie czcionek, pobieranie glifów (wizualna reprezentacja liter) oraz odczytywanie atrybutów czcionek.

Skupmy się na najbardziej popularnym wczytywaniem czcionek, czyli wczytywaniem z pliku:

Zauważ, że SFML nie wczytuje czcionek systemowych automatycznie, a więc coś takiego font.loadFromFile(„Courier New”) nie zadziała, ponieważ SFML potrzebuje nazwy pliku, nie nazwy czcionki oraz program nie znajdzie się w magiczny sposób do folderu z czcionkami w twoim systemie. Jeżeli chcesz wykorzystać jakąś to musisz ją dostarczyć razem z resztą plików potrzebnych do twojej gry.

Czasami SFML ma problemy z czcionkami z pozornie nie oczywistych powodów. Wtedy pierwszym z błędów, które sie pojawiają to komunikat w konsoli: „unable to open file”. Upewnij się  czy podałeś prawidłową ścieżkę do pliku (używaj ścieżek bezpośrednich) oraz z dobrym rozszerzeniem pliku. Jeżeli jesteś pewien że nazwa jest poprawna to zauważ że w przypadku gdy uruchamiasz grę z poziomu IDE to ścieżka bezpośrednia zaczyna się tam gdzie jest kod programu (zazwyczaj), a gdy uruchamiasz ją z pliku wykonywalnego (exe) to ścieżka bezpośrednia rozpoczyna się tam gdzie jest plik exe.

Czcionkę możesz wczytać także z pamięci (loadFromMemory) lub własnego strumienia danych (loadFromStream).

SFML wspiera najczęściej spotykane rozszerzenia czcionek, pełna lista jest dostępna w dokumentacji API.

 

Wyświetlanie tekstu


Do rysowania tekstu używamy klasy sf::Text i jest bardzo prosta w użyciu:

Tekst może także ulegać przekształceniom (transform) posiada pozycję, rotację i skalę. Funkcje są w większości takie same jak dla sf::Sprite i działają na tej samej zasadzie, wszystko jest wyjaśnione w poradniku o Przekształcaniu obiektów.

 

Rozwiązywanie problemów ze znakami nienależącymi do ASCII


Prawidłowe przechwytywanie znaków, które nie należą do ASCII może być dla nas (europejczyków) może być dosyć istotne, ale jest dosyć trudne. Wymaga to dobrej wiedzy kodowania podczas interpretacji danych znaków. Istnieje dosyć proste rozwiązanie: należy skorzystać z wide literal string (wybaczcie, ale nie wiem jak to ładnie przetłumaczyć). Wygląda to w następujący sposób:

Dodając to L przed tekstem dajemy kompilatorowi informację, że chcemy skorzystać z szerokich znaków. Generalnie to rozwiązanie nie pomaga jeżeli chodzi o niektóre znaki, ale w przypadku polskich czcionek daje sobie radę.

 

Tworzenie własnych klas do obsługi tekstu


 Jeżeli sf::Text ma twoim zdaniem zbyt dużo ograniczeń, albo po prostu jest dla ciebie zbyt słabo rozbudowany możesz stworzyć własną klasę obsługującą tekst. Wszystko czego potrzebujesz do stworzenia własnej klasy znajduje się w sf::Font.

Po pierwsze musisz pobrać teksturę, któa zwiera wszystkie pre-renderowane glify o określonym rozmiarze:

Zauważ, że glify są dodawane dopiero podczas gdy jest pobierana tekstura, jest to spowodowane dużą ilością znaków (więcej niż 100000) i dlatego nie są wczytywane podczas wczytywania czcionki, zamiast tego są wczytywane podczas uruchomienia getGlyph (zobacz poniżej).

Aby zrobić coś użytecznego z teksturą glifa musisz pobrać jej koordynaty, które są zawarte w:

character to kod UTF-32 glifa, którego chcesz pobrać. Musisz także podać wielkość znaków oraz to czy znaki mają być pogrubione czy normalne.

sf::Glyph posiada 3 członków:

  • textureRect zawiera współrzędne glifu,
  • bounds ograniczający prostokąt glifa, który pomaga w ustawieniu go w stosunku do linii bazowej tekstu,
  • advance to poziomy offset, który ma na celu pobranie następnego glifa w tekście.

Wreszcie możesz pobrać kilka właściwości twojego tekstu, takie jak wysokość linii czy kerning.

Oryginalny artykuł

Kształty w SFML

W SFML masz dostęp z góry do kilku typów prostych kształtów, a także nic nie stoi na przeszkodzie abyś mógł stworzyć kilka własnych. Tutaj dowiesz się jak obsługiwać potrzebne do tego klasy.

Wspólne właściwości kształtów


Przekształcenia (pozycja, skala, rotacja)

Wszystkie te przekształcenia są dostępne dla każdego z kształtów w SFML i zostały opisane w poradniku Przekształcenia kształtów.

Kolor

Aby zmienić kolor wewnątrz obiektu musisz użyć setFillColor.

Kontur

Możesz ustawić także dowolny kolor konturu figury oraz jego grubość.

 

W przypadku gdy ustawimy grubość konturu > 0 to figura się powiększa o jej grubość np jeżeli mamy koło o promieniu 10 i dodamy kontur o grubości 5 to cała figura będzie miała promień o długości 15. Jeżeli chcesz aby kontur był rysowany wewnątrz figury, czyli żeby figura nie powiększała się ustaw grubość konturu na ujemną.

 

Tekstura

Tak jak sprite’y figury mogą korzystać z tektur:

Kontur nie jest teksturowany, aby odwołać używanie tektury użyj setTexture(NULL).

 

Rysowanie kształtów


Odbywa się ono w tradycyjny sposób dla wszystkich figur.

 

Wbudowane klasy kształtów


Prostokąt

Aby narysować prostokąt musisz użyć sf::RectangleShape. Konstruktor przyjmuje jako argument jego wielkość (szerokość i wysokość).

Koło

Ta figura jest reprezentowana przez sf::CircleShape. Posiada dwa atrybuty: promień oraz opcjonalny który decyduje o tym z ilu punktów się się składa. Decyduje to o „jakości” okręgu. Im większy kształt tym więcej boków będzie potrzebował.

Wielokąty foremne

Wielokąty foremne charakteryzują się tym że powstają na okręgu i ich boki są równej długości, dzięki temu je także robimy za pomocą sf::CircleShape.

Figury wypukłe

Do rysowania figur wypukłych służy klasa sf::ConvexShape. Co musisz pamiętać przy ich rysowaniu to aby rozmieszczać kolejne punkty figury w kierunku zgodnym lub przeciwnym do wskazówek zegara, nie rób tego w sposób losowy.

SFML nie posiada klasy do rysowania figur wklęsłych, ale możesz się w tym celu posłużyć tą klasą o ile pierwszym punktem będzie środek ciężkości figury.

Linie

Linie nie mają swojego odpowiednika w SFML z prostego powodu. Jeżeli twoja linia ma jakąś grubość to jest prostokątem, jeżeli nie może być narysowana za pomocą prymitywów.

Oraz linia-prymityw:

Aby dowiedzieć się więcej o prymitywach zapraszam do poradnika o VertexArray.

 

Tworzenie własnego kształtu-klasy


Możesz poszerzyć typy kształtów o te napisane przez siebie. Aby to zrobić musisz dziedziczyć po sf::Shape i napisać 2 funkcje:

  • getPointCount do pobrania liczby punktów
  • getPoint do pobrania punktu o określonym indexie

Musisz także używać klasy update() do zaktualizowania stanu swojej figury. Poniżej jest gotowy przykład gotowej klasy rysującej elipsę.

Antyaliasing w kształtach


Czyli wygładzenie krawędzi, które możemy ustawić w ustawieniach okna

Nie każda karta graficzna może go obsługiwać, więc efekt nie musi być widoczny na każdym komputerze.

Oryginalny artykuł

Sprite’y i tekstury

Na początku lekcji warto sobie uzmysłowić czym jest tekstura oraz czym jest sprite. Tekstura to jakiś obraz (np wczytany z pliku), a nazywamy go teksturą (Texture), a nie obrazem (Image) ponieważ my go będziemy mapowali do obiektów 2D. Sprite to nic innego jak „teksturowany” kwadrat.

W SFML do przechowywania tekstur służy sf::Texture, a do sprite’ów sf::Sprite.

 

Wczytywanie tekstur


Możemy wczytywać tekstury na 3 sposoby: z pliku (loadFromFile), z pamięci (loadFromMemory) oraz z jakiegoś napisanego przez nas strumienia danych (loadFromStream). Jednak my podczas tego tutoriala zajmiemy się najbardziej popularnym wczytywaniem z pliku.

W przypadku gdy nie uda nam się wczytać pliku (np. jest nieprawidłowe rozszerzenie lub zła nazwa pliku) funkcja zwraca false. Listę wspieranych przez SFML formatów obrazów znajdziesz w dokumentacji.

Wszystkie funkcje do wczytywania posidają także opcjonalny argument, który pozwala nam wczytać fragment tekstury.

sf::IntRect to klasa, która w matematyczny sposób reprezentuje kwadrat. Pierwsze 2 argumenty to pozycja na której się zaczyna, kolejne dwa to szerokość i wysokość.

 

Jeżeli nie chcesz wczytywać tekstury, a raczej wolisz wypełnić ją bezpośrednio z jakiejś tablicy pikseli możesz to zrobić. Na początku musisz stworzyć teksturę, którą możesz wypełnić później.

Pamiętaj, że teraz zawartość tekstury jest niezdefiniowana. Aby ją uzupełnić możesz to zrobić na kilka sposobów:

Te sposoby przedstawiają sposób zaktualizowania całej tektury, możesz także zaktualizować fragment, ale o tym informacje znajdziesz w dokumentacji.

Istnieją 2 właściwości, które decydują o tym w jaki sposób będzie renderowana tekstura.

Pierwszą z nich jest wygładzenie (smooth), dzięki któremu piksele są mniej widoczne. Można to włączyć używając:

Druga właściwość to powtarzanie, które działa tylko wtedy gdy obrazek który ma być wyświetlany jest większy niż tekstura, czyli np wyświetlany kwadrat o wymiarach 100×100, a nasza tekstura ma wymiary 25×25, wtedy może zostać powtórzona.

Sprite’y


Skopiowanie tekstury do sprite’a jest proste. Możemy podać teksturę w konstruktorze sprite’a lub poprzez użycie metody:

sf::Sprite sprite(texture);
sprite.setTexture(texture);

Rysowanie wygląda w ten sposób:

Możesz wczytać także fragment tekstury:

Możesz także zmieniać kolor sprite’a, ewentualnie możesz też tego użyć do zmiany przezroczystości.

Sprite’y poniżej mają tę samą teksturę, lecz różne kolory:

Sprite’y możesz także przekształcać:

Standardowo przekształcenia pokazane powyżej są dokonywane względem lewego górnego rogu, jeżeli chcesz je wykonywać względem innego punktu np środa sprite’a musisz skorzystać z:

 

Problem białego kwadratu


Jeżeli ci się zdarzyło, że mimo wczytania tekstury bezproblemowo i ustawienia jej sprite’owi, po wyświetleniu masz biały kwadrat to ten paragraf poradnika jest skierowany dla ciebie.

Jest to bardzo często spotykany błąd, problem leży w tym, że gdzieś w kodzie przestał istnieć wskaźnik do twojej tekstury, bo sprite nie kopiuje jej lecz pobiera wskaźnik do niej. W momencie gdy tekstura jest niszczona wskaźnik wskazuje na puste bity w pamięci. Prawdopodobnie twoja funkcja wygląda mniej więcej tak:

Musisz zawsze posiadać swoją teksturę w pamięci inaczej ten błąd będzie się powtarzał.

 

Używaj jak najmniej tekstur


Staraj się używać jak najmniejszej liczby tekstur jak to możliwe, pamiętaj że zmiana tekstury to ciężka operacja dla karty graficznej. Rysowanie wielu sprite’ów używających tej samej tekstury przynosi lepsze efekty. Dlatego lepiej jest korzytsać np. z tzw. tilesets (atlasów tekstur). Jest to zdecydowanie wydajniejsze.

Oryginalny artykuł

Rysowanie obiektów 2D

Z tego poradnika dowiesz się jakie obiekty można narysować obiekty, a także jak napisać własne klasy, które będziesz mógł narysować.

 

Rysowanie


Aby narysować obiekty w łatwy sposób potrzebujesz do tego specjalnej klasy sf::RenderWindow, która dziedziczy po sf::Window, co oznacza, że wszystko co się nauczyłeś jest wciąż aktualne i wygląda w ten sam sposób.

RenderWindow zawiera bardziej zaawansowane funkcje, które pozwalają nam manipulować oknem. Dzisiaj zajmiemy się 2 z nich: clear i draw. Robią dokładnie to jak się nazywają: clear czyści ekran, draw zajmuje się rysowaniem obiektów.

Wywoływanie metody clear jest ważne i musi odbyć się przed rysowaniem wszelkich obiektów, jeżeli jej nie wywołasz to mogą pozostać piksele z poprzedniego rysowania obiektów. Jeżeli byś poruszał wtedy postacią moglibyśmy uzyskać taki efekt:

(Win 7,8,8.1 straciły ten feature, ale na szczęście Win10 go odzyskał ;] )

Wywołanie display także jest konieczne to prawidłowego działania, ponieważ podczas wywoływania draw wszystkie obiekty są kopiowane do bufora (o którym porozmawiamy za chwilę), a wywołanie display powoduje uwolnienie tych obiektów z bufora i wyświetlenie ich na ekranie.

Powinno się wywoływać te metody wg kolejności:

  • clear – do czyszczenia ekranu
  • draw – do rysowania obiektów
  • display – do wyświetlenia obiektów

 

Jakie obiekty można rysować?


W SFML jest przygotowanych kilka typów obiektów, sprite’y (rysowanie obrazków), tekst (wiadomo) oraz kształty. Niektóre kształty są przygotowane, a także mamy klasę, która pozwala nam rysować własne wielokąty (VertexArray).

 

Rysowanie własnej klasy


Generalnie możemy narysować każdy obiekt, który dziedziczy po sf::Drawable. Zrobienie tego nie jest trudne, pokaże to na hipotetycznej klasie, w której mamy Sprite’a, który reprezentuje naszą postać w grze oraz kilka cech typowych dla gier:

To co musi mieć klasa dziedziczona po Drawable to metoda prywatna draw, tylko wtedy możemy wywołać narysowanie naszego obiektu poprzez window.draw(nasz_obiekt). Możesz powiedzieć, że to jest mało przydatne przecież można w tym wypadku podać sprite’a naszej klasy poprzez postac.sprite i narysować go bez bawienia się w dziedziczenie. Masz rację można, tylko że nie zawsze podajemy naszą teksturę jako publiczną oraz nie zawsze nasza postać składa się z jednego elementu. Załóżmy, że chcemy mieć super zaawansowaną kolizję, która będzie obejmowała trafienie w nogi, ręce, głowę i tors, które zrobimy z odpowiednio, linii, linii, koła i prostokąta:

Schematyczna postać składająca się z różnych elementów

A nasz kod rysujący by wyglądał tak:

Wtedy dziedziczenie nabiera sensu bo te wszystkie linie wywołasz poprzesz window.draw(postac), a gdy cię najdzie ochota na stworzenie kolejnej takiej postaci po prostu wywołasz window.draw(postac_2), a  nie kolejną masę tych samych linii. To tyle jeżeli chodzi o mój wywód „dlaczego warto dziedziczyć klasę Drawable”.

 

Rysowanie off-screen


Zanim przejdziemy dalej, to może uświadomimy sobie czym właściwie jest rysowanie off-screen (niestety polskiego określenia na to nie kojarzę). Jest to skopiowanie do pamięci następnej wyświetlonej klatki, tzn podczas rysowania obecnej klatki już w chwili obecnej jest tworzona kopia obrazu do klatki następnej. Najlepiej to prezentuje obrazek poniżej:

 

Przedstawiony tutaj sposób prezentuje narysowanie elementu na texture zamiast bezpośrednio do okna. Używamy tutaj sf::RenderTexture zamiast sf::RenderWindow.

 

Rysowanie z różnych wątków


Jeżeli korzystasz z wielu wątków, powinieneś wiedzieć jak napisać poprawnie wątek rysujący wszystkie elementy. Warto zapamiętać, że powinieneś zdezaktywować okno zanim zaczniesz je używać w innych wątkach, ponieważ okno nie może być aktywne w wieli wątkach jednocześnie.

Jak widać nie musisz włączać okna w wątku renderującym, SFML robi to za ciebie. Przypominam o tym, że najbezpieczniej jest tworzenie okna i przechwytywania eventów w głównym wątku.

Oryginalny artykuł