Gra 2D, część 4: Piszemy Hall of Fame
29.01.2010 - Łukasz Milewski
![]() ![]()
Każdy z nas lubi wygrywać, być najlepszym ;-) Dlatego, aby uatrakcyjnić naszą grę powinniśmy zaspokoić tę potrzebę gracza. W tej części kursu stworzymy ekran, na którym gracz będzie mógł umieścić swoje imię gdy zdobędzie więcej punktów niż inni.
Poprzedni artykuł - mapa kaflowa Następny artykuł - odtwarzamy dźwięk Plan działaniaSkonstruujemy Hall of fame, czyli listę najlepszych graczy, posortowaną według ilości punktów. Na początek nauczymy się korzystać z czcionek bitmapowych. Następnie na podstawie takiej czcionki wyświetlimy prosty hall of fame. Ostatnim krokiem będzie zaprogramowanie ekranu, na którym można wpisać swoje imię. Zaprogramujemy dwa sposoby wpisywania imienia: z klawiatury lub klikając na odpowiednie litery. Zaczynamy!
Kroki początkoweWgraj sobie nową teksturę. Umieść ją w katalogu data. Zawiera ona wszystko to, co poprzednio oraz czcionkę. Zauważ, że napisy są na szachownicy. Dzięki temu łatwiej jest narysować litery. Grafika jest robocza, co oznacza że zmienimy ją gdy gra będzie gotowa. Tutaj znajdziesz kod, od którego zaczynamy. Czcionka bitmapowaPierwszym efektem będzie czcionka rastrowa (znana również jako czcionka bitmapowa). Oznacza to, że wyświetlane litery są zapisane w pliku z grafiką jako bitmapa. Naszym celem jest wyświetlanie słów złożonych z liter i cyfr oraz znaków specjalnych. Zacznijmy od zdefiniowania interfejsu klasy Text. Chcemy mieć możliwość ustawienia wielkości tekstu oraz warstwy, na której będzie on widoczny. Chcielibyśmy także móc narysować literę, cyfrę, znak specjalny (np. podkreślenie), cały napis oraz liczbę. Dodatkowo, potrzebujemy specjalnej metody rysującej, aby nie powtarzać niepotrzebnie kodu. Kod może wyglądać np. tak (plik Text.h): Pokaż/ukryj kod
Parameter width w DrawNumber określa, jaka ma być minimalna długość liczby (gdy jest zbyt krótka, wyrównujemy ją odstępami z lewej strony). Przejdźmy do implementacji. Potrzebujemy funkcji, która zamienia liczbę na string (można to zrobić łatwo przy pomocy boost::lexical_cast, ale staramy się ograniczyć wykorzystanie boost do klasy shared_ptr). Do pliku Utils.h wpisujemy taką treść:
Następny krok to rysowanie. Zajdzie potrzeba manipulowania macierzą projekcji, dlatego z klasy App przenosimy fragment metody App::Resize. Obecnie powinna ona wyglądać tak:
Ustawienie macierzy projekcji jest teraz w klasie Renderer. Do pliku Renderer.cpp na koniec dopisujemy:
a do pliku Renderer.h do klasy Renderer w zasięgu publicznym dorzucamy deklaracje:
Znaczenie tych kodów zostało wytłumaczone w artykule Tworzenie okna i wyświetlanie animowanego sprite'a Spójrzmy na metodę Text::Draw. Jej zadaniem jest wyświetlenie na ekranie sprite'a z atlasu tekstur z pozycji (tex_x, tex_y) na pozycję (pos_x, pos_y). Metoda ta zakłada, że sprite jest wielkości (32,32) oraz ma być wyświetlony na ekranie w wielkości ustawionej metodą SetSize (pola m_width, m_height). Wyświetlanie sprite'a jest w pewien sposób specjalne Jest on bowiem wyświetlany tak, jakby (0,0) było w lewym dolnym rogu ekranu, a (1,1) w prawym górnym rogu. Inaczej jest wyświetlana mapa i gracz. Dla gracza pozycja (0,0) oznacza, że jest on na początku mapy. Nie znaczy to jednak, że jest w lewym dolnym rogu ekranu! Aby uzyskać taki efekt, musimy ustawić macierz projekcji na identyczność oraz rzut ortogonalny od początku (tak, jak w artykule pierwszym - metoda App::Resize). Zanim to jednak zrobimy, powinniśmy odłożyć na stos stare macierze - MODELVIEW i PROJECTION. Nie chcemy przecież, aby Text::Draw wpływało w jakikolwiek sposób na rysowanie innych elementów (np. przesuwało je). Przydatna jest struktura danych, która pozwala dodawać elementy i je z niej pobierać. Chcemy, aby pobrany element był zawsze tym najpóźniej włożonym (elementy wyjmujemy w kolejności odwrotnej do wkładania). Można to przyrównać do stosu kartek. Zawsze na górze jest tylko jedna - ta ostatnio położona. Aby zobaczyć kolejną kartkę trzeba podnieść pierwszą. Struktura, która zachowuje się w ten sposób nazywana jest stosem. W naszym przypadku na stos odkładamy macierze OpenGL. Aby odłożyć macierz na stos, należy ustawić ją jako aktywną - przez glMatrixMode. Następnie możemy posłużyć się funkcjami glPushMatrix i glPopMatrix do obsługi stosu macierzy. Po ustawieniu macierzy projekcji od nowa, a macierzy MODELVIEW na identyczność, wystarczy narysować sprite'a przy pomocy znanej nam już metody Renderer::DrawSprite. Pokaż/ukryj kod
Posiadając metodę Draw, możemy zdefiniować kolejne proste metody: DrawDigit, DrawLetter, DrawSpecial. Kolejno wypisują one cyfry, litery oraz znaki specjalne (np. podkreślenie). Zadanie tych metod sprowadza się do obliczenia, gdzie w atlasie znajduje się odpowiednia grafika i wywołania metody Draw. Poszczególne znaki są zapisane w pliku tak, jak widać na załączonym obrazku (kolejny raz podkreślmy, że jest to grafika robocza - zostanie zmieniona po ukończeniu kodu gry).
Na podstawie powyższej ilustracji łatwo wyznaczyć pozycje kolejnych liter (w teksturze obrazek z czcionką jest przesunięty w dół). Pokaż/ukryj kod
Na bazie tych metod możemy zbudować kolejne: DrawText oraz DrawNumber. Text::DrawText iteruje po kolejnych znakach i przy pomocy funkcji z nagłówka cctype sprawdza, czy znak jest literą, cyfrą czy podkreśleniem. Wszystkie inne znaki są pomijane. Gdy metoda pozna typ znaku, od razu wywołuje odpowiednią metodę spośród tych, które przed chwilą wymieniliśmy. Pokaż/ukryj kod
Metoda Text::DrawNumber też jest bardzo leniwa. Najpierw przy pomocy fukncji IntToStr zamienia liczbę na napis. Następnie sprawdza, czy liczba jest dobrze wyrównana (dodaje wiodące zera do osiągnięcia długości width). Ostatecznie wywoływana jest metoda DrawText z odpowiednim tekstem, reprezentującym daną liczbę.
Możemy spróbować wypisać coś na ekranie. Wystarczy do metody App::Draw dopisać takie linijki (i dodać nagłówek Text.h). Powinny być dodane zaraz po narysowaniu gracza.
(3 ocen) |
Copyright © 2008-2010 Wrocławski Portal Informatyczny
design: rafalpolito.com