Platformówka - jak to się robi?
24.11.2009 - Marcin Milewski
Następny artykuł - poruszanie postacią Choć tworzenie gier komputerowych nie jest zadaniem łatwym, to z całą pewnością można stwierdzić, że jest zajęciem ciekawym. Celem cyklu, który rozpoczyna się tym artykułem jest stworzenie gry platformowej w stylu Mario. Poniżej przedstawiamy film z gry, którą zaraz zaczniemy pisać. Do zrozumienia tej oraz kolejnych części przydatna będzie znajomość języka programowania C++ w stopniu podstawowym oraz podstaw użycia biblioteki OpenGL (lub trochę czasu na poeksperymentowanie z przykładami). Będziemy też potrzebować bibliotek SDL oraz boost. Wszystkie one są dostępne na najpopularniejsze platformy, więc nie powinno być kłopotów z ich instalacją. Zalecamy wykorzystanie ich najnowszych stabilnych wersji. Tworzenie okna i wyświetlanie animowanego sprite'aNa początku naszej zabawy w tworzenie gry dowiemy się, jak stworzyć główne okno gry oraz jak wyświetlić w nim animowany obrazek. Oto efekt, jaki chcemy uzyskać: Jak działają gry?Ogólnie rzecz biorąc, gra składa się z części logicznej (zarządzanie stanem aplikacji) oraz wizualnej. Częścią logiczną w każdej aplikacji zarządza pewien mechanizm, na przykład w systemach operacyjnych są to zdarzenia (naciśnięcie przycisku, wprowadzenie litery, zmiana rozmiaru okna, itp.). Podstawowym mechanizmem działania gier nie są zdarzenia, lecz pętla czasu rzeczywistego. Na czym to polega? Otóż gra, od rozpoczęcia aż do zakończenia, wykonuje w kółko kilka operacji. Oto ogólny schemat:
Tworzenie oknaPo wstępie teoretycznym przejdziemy do pisania aplikacji. Wykonywanie aplikacji rozpocznie się w pliku main.cpp – zostanie utworzona tam instancja klasy App, której zadaniem będzie stworzenie okna oraz wykonywanie pętli głównej. Trzy argumenty, które znajdują się w konstruktorze klasy App to odpowiednio szerokość oraz wysokość tworzonego okna, a ostatni parametr odpowiada za tryb pełnoekranowy (false stworzy okno, true stworzy okienko w trybie pełnoekranowym).
Przyjrzyjmy się teraz klasie App. Pokaż/ukryj kod
Poza metodami, których istnienie jest podyktowane wykorzystaniem mechanizmu pętli czasu rzeczywistego do konstrukcji gry, zauważamy pole m_screen. Jest to struktura wykorzystywana przez bibliotekę SDL do identyfikacji elementu, po którym można rysować. SDL udostępnia co prawda mechanizmy do rysowania sprite'ów, jednak my decydujemy się na wykorzystanie do tego celu biblioteki OpenGL, która daje dużo więcej swobody w sposobie konstruowania obrazu. Drugą ciekawą rzeczą w powyższym fragmencie kodu jest argument metody Update. Nazwa dt to skrót od delta time, czyli znany nam z lekcji fizyki upływ (zmiana) czasu - Δt. Ponieważ jednak naszym obecnym celem jest stworzenie okna, ten argument jest dla nas chwilowo bez znaczenia. Przyjrzyjmy się teraz implementacji metod klasy App. Na początku pliku App.cpp należy dołączyć dwa pliki:
Najpierw omówimy metodę Run, która będzie korzystała z pozostałych metod realizujących pojedyncze zadania. Pokaż/ukryj kod
Na początku inicjalizujemy bibliotekę SDL, tak, aby utworzyła nam okno, które będzie udostępniało podwójne buforowanie. Dalej inicjalizujemy biblitekę OpenGL. Kolejne wywołania to odpowiednio: ustawienie koloru czyszczenia ekranu (kolor RGB(0,0,0) czyli czarny), włączenie bufora głębokości i ustawienie trybu jego działania. Należy się słowo wyjaśniania odnośnie bufora głębokości. Jest to technika, która pozwala na rysowanie obiektów w dobrej kolejności. Dobrej - to znaczy, że widoczne będą zawsze obiekty, które są bliżej obserwatora niezależnie od kolejności rysowania. Można nie korzystać z tej techniki, jednak należy wtedy samemu zadbać, aby obiekty były rysowane od najdalszego planu do najbliższego. Pozostała część metody Run to pętla główna. Zapewne nie potrzeba żadnej pomocy w identyfikacji odpowiedzialnych za kolejne funkcjonalności kawałków kodu, które implementują główną pętlę gry. Pole is_done jest flagą informującą, czy należy zakończyć wykonywanie pętli głównej (wartość true) czy ją kontynuować (wartość false). Dalej następuje obsługa zdarzeń (obsługa wejścia, reakcja okna na akcję użytkownika) oraz wyliczenie czasu, jaki upłynął od utworzenia ostatniej klatki. W tym właśnie miejscu wyliczamy, ile czasu upłynęło i przekazujemy tę informację do metody Update. Na koniec pozostaje nam już tylko narysować wygenerowaną klatkę. Zastanów się, które z elementów pętli głównej można zamienić miejscami, a dla których nie ma to sensu. Pokaż/ukryj odpowiedź
Przejdźmy teraz do krótszych metod. Metoda Update na razie jest pusta, ponieważ nie stworzyliśmy jeszcze żadnych obiektów, które zmieniają swój stan na podstawie upływu czasu. Metoda Draw czyści bufory koloru oraz głębi, a następnie nakazuje wyświetlić klatkę.
Metoda przetwarzająca zdarzenia pobiera kolejne zdarzenia z kolejki i albo je obsługuje albo odrzuca.
Została nam ostatnia metoda. Oczywiście nie mniej ważna - wręcz przeciwnie, jedna z ważniejszych. Zmienia ona rozmiar okna. Wykorzystuje do tego funkcję SDL_SetVideoMode, która zwraca wskaźnik do odpowiedniej powierzchni, po której można rysować (lub 0 w przypadku niepowodzenia). W drugiej części kodu znajdują się instrukcje, które informują OpenGL o tym, jak ma zagospodarować stworzone okno. Na razie chcemy, aby wyświetlał obraz na całym oknie (funkcja glViewport), do którego będziemy odnosić się używając współrzędnych [0,1]x[0,1] (punkt (0,0) jest w lewym dolnym rogu, a (1,1) - w prawym górnym) - funkcja glOrtho. Więcej szczegółów o tych przekształceniach można znaleźć pod adresem http://glprogramming.com/red/chapter03.html . Na koniec przełączamy OpenGL na tryb modelowania, w którym będziemy rysować obiekty.
W ten sposób skończyliśmy pisać kod odpowiedzialny za tworzenie okienka. Wrócimy jeszcze do niego, gdy będziemy chcieli dodać elementy do gry. W ramach ćwiczeń można pobawić się naszą aplikacją, zmieniając kilka rzeczy (np. kolor tła, usunięcie czegoś z obsługi zarzeń) i obserwując, jakie będą konsekwencje. (7 ocen) |
Copyright © 2008-2010 Wrocławski Portal Informatyczny
design: rafalpolito.com