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ł


  • Kamil

    Kiedy chcę załadować czcionkę, to sfml dopisuje do mojego error’a w oknie konsoli „(unable to create font face)”.
    Czcionka jest w formacie .ttf. Co może być przyczyną?

    • Bez kodu ciężko stwierdzić, może robisz coś takiego (możliwa przyczyna + rozwiązanie): http://pastebin.com/6DUgSAqE . Ewentualnie podrzuć mi swój kod (tutaj) tylko że wrzuć na http://pastebin.com/

      • Kamil
        • Kamil

          Problem rozwiązany, było to spowodowane tym gdzie Visual cpp szuka danego pliku w przypadku ścieżki bezpośredniej. Jeśli odpalamy z poziomu Visuala, to będzie jej szukał w miejscu gdzie jest zapisywany kod, jak odpalimy bezpośrednio z .exe to wtedy będzie szukał tam gdzie jest plik exe.

          • Jak zwykle rozwiązanie nadchodzi samo do głowy kilka minut po prośbie o pomoc 🙂

  • pw1602

    Mam problem z wyświetleniem tekstu, a głównie chodzi o wczytanie go i wyświetlenie na ekranie. Chciałem zrobić pole, w którym pojawiałby się tekst wpisany przez użytkownika litera po literze, coś jak wprowadzanie nazwy postaci w grach tylko nie wiem, jak się za to zabrać. Czytałem, że jest funkcja TextEntered dla wejścia i String dla wyjścia, ale co z tego, jak nie potrafię tego użyć, by poprawnie działało, a kod z użyciem tych funkcji jest dla SFML 1.6. Szukałem w dokumentacji, ale najwyraźniej nie potrafię jej jeszcze czytać. Czy byłaby możliwość zrobienia poradnika o tym lub po prostu w jakiś sposób pomóc mi w komentarzu? Prosiłbym o kod, jeśli to możliwe z rozwiązaniem problemu.

    • Kod z SFML 1.6 ma to do siebie że jest dość łatwy do przekonwertowania na SFML 2.x.x (wystarczy w 1 miejscu zamienić duże znaki na małe).

      Kiedyś miałem wielkie plany stworzenia klasy, która umożliwiałaby tworzenie łatwych w użyciu kontrolek (textboxów, okien, przycisków), jednakże potrzebowałem tego do projektu dość szybko, a później plany napisania tej klasy zostały porzucone i zapomniane.

      Tutaj masz kod, który powinien działać: http://pastebin.com/CG8gc0UK . Całość jest oparta na uboższej wersji mojej klasy, linki masz w komentarzach.

      • pw1602

        W jaki sposób wyświetlić tego stringa? Bo nie wiem czy jest taka możliwość, a myślałem nad zrobieniem funkcji, która by wyłapywała wciśnięte litery i dopiero wyświetlała. Da się to rozwiązać szybko i bezboleśnie?

        • Po prostu przypisujesz ustawiasz obiektowi sf::Text tego stringa, teraz przy każdym wciśnięciu klawisza w widoczny sposób dopisujesz nowy znak. Możesz jeszcze wyłapywać wciśnięcia innych klawiszy np. backspace i wtedy usuwać ostatni znak, etc. Ja podałem ci jedynie najprostszą wersję przechwytywania znaków.
          http://pastebin.com/GDFDsvW5

          Nie obiecuję, ale może coś się szerzej pojawi na ten temat na blogu jeżeli faktycznie jest na to zapotrzebowanie.

          • pw1602

            Właśnie kombinowałem, ale najwyraźniej przekombinowałem, bo zapomniałem o setString…

            Można by ten temat poruszyć w „HowTo”, jako tworzenie postaci lub w „Piszemy Grę RPG”, również jako tworzenie postaci lub coś innego 😉

          • Wpis na ten temat pojawi się w piątek.

  • lama

    A jak wypisać zawartość zmiennej

    • Musisz dokonać konwersji tej liczby na string, po czym możesz ten string wykorzystać w klasie Text (setString)

  • Danthee

    text.setColor(sf::Color::Yellow); was called deprecated

    o co chodzi?