Bardzo ważnym elementem nauki programowania jest też element rozrywki i po prostu czerpanie z tego przyjemności. Z okazji zbliżających się świąt mamy dla Ciebie mini prezent — krótki kurs, podczas którego stworzymy grę w Javie! Nie martw się, to nie trudne, a może Ci przynieść masę radości!W ramach tego mini-kursu stworzymy od podstaw prostą grę, którą będziesz mogła sprezentować najbliższym lub stworzyć razem z młodszym członkiem rodziny, być może inspirując go do nauki programowania :) W tej serii wpisy będą pojawiać się częściej niż zazwyczaj — niestety z racji innych obowiązków nie publikujemy tak często, jak byśmy tego chcieli.
Nie przedłużając — przechodzimy do dzieła!
Footrzasta — fabuła, zasady i o co chodzi
Na początku może słowo wyjaśnienia w kwestii tytułu — z uwagi na trzeciego autora tego bloga, oczywistym bohaterem gry będzie kot. Nie byle jaki kot, bo będzie to Tesla, znana w niektórych kręgach jako “futrzasta”. Tesla ma też przedziwne upodobanie do gryzienia w stopy stąd tytuł właściwie napisało życie ;)
Gra będzie grą platformową, w której głównym celem jest dotarcie do końca planszy. Po drodze bohater musi unikać przeszkód — myszy, stóp, oraz legowisk, które utrudniają osiągnięcie celu (każde z nich powoduje utratę jednego ze smakołyków, których ilość nie może spaść do zera). Aby móc iść dalej kotek musi oczywiście jeść, jednak nie jest to takie proste — z uwagi na ogromny apetyt przejedzenie się spowoduje spowolnienie i ‘ociężałe’ ruchy, a na dodatek Tesli upodobania kulinarne są … oryginalne — nie wszystko jej przypadnie do gustu.
Technologie i nasz cel
Zacznijmy może od celu tej serii — niestety nie nauczymy Cię tworzyć gier, na których zarobisz miliony ;) Celem tego kursu jest przede wszystkim dobra zabawa — bo kto by nie chciał stworzyć własnej gry ;) — oraz nauka programowania przy okazji :) O ile poznasz zasady, jakimi rządzi się tworzenie gier, będziemy wykorzystywać dość ‘czyste’ narzędzia — współcześnie wiele gier tworzy się korzystając z gotowych silników, które dbają o rzeczy takie jak np fizyka — my napiszemy taki silnik samodzielnie. Dodatkowo w kilku miejscach ‘przesadzimy’ technologicznie — przykładowo wykorzystamy Spring’a, bardziej po to, aby sobie poćwiczyć korzystanie z niego niż z dużej potrzeby :)
Jeśli chodzi o technologie, to skorzystamy z biblioteki LWJGL (to akronim od Light Weight Java Gaming Library), które daje nam dostęp do OpenGL — silnika graficznego, który przez dłuuuugie lata był podstawą większości gier i wszelkiej maści produktów związanych z wyświetlaniem grafiki. O ile bezpośrednio nie wykorzystasz tej wiedzy do tworzenia gier np. na Androida, o tyle istnieją biblioteki bardzo podobne w zachowaniu, które można z powodzeniem wykorzystać w systemach Android (np. libGDX z tych bardziej popularnych). Być może zainspirujemy Cię i zostaniesz sławnym producentem gier? Nie zapomnij podesłać wtedy Tesli jakiegoś smakołyka ;)
Podsumowując — w tym kursie przejdziemy przez podstawy pracy z grafiką, zasady działania gier oraz stworzymy pełnoprawną, działającą grę. Naszym głównym celem jest jednak nauka i zabawa, więc nie zawsze będziemy się trzymali ‘sztuki’ wg profesjonalnych twórców gier. W ramach praktyki w naszej grze wykorzystamy także Springa (a także po to, aby przełamać stereotyp, że jest to framework do aplikacji webowych).
Grę będziemy także rozwijać korzystając z repozytorium Git, co ułatwi każdemu pobranie jej kopii. Przed kolejną lekcją spodziewajcie się wpisu na ten temat :)
OpenGL
W tym miejscu warto powiedzieć parę słów o OpenGL — bibliotece graficznej, z której będziemy korzystać. Biblioteka ta pozwala na obsługę grafiki zarówno dwu- jak i trój-wymiarowej i działa na większości platform sprzętowych, jakie są dostępne na rynku. Sam standard nie jest nowy (jego początki sięgają przełomu lat 80’tych i 90’tych), ale cieszy się niesłabnącą popularnością dzięki swojej uniwersalności (sama biblioteka jest dość niskopoziomowa, co pozwala na jej wykorzystanie niemal do wszystkiego), prostocie obsługi (choć pierwsze linijki kodu zapewne Cię przerażą, to API jest czytelne i dobrze zorganizowane) oraz wydajności (wiele kart graficznych wspiera operacje, które OpenGL wykonuje, przyspieszając je — sama biblioteka wymaga kompilacji pod kątem systemu, w którym działa).
Ponieważ biblioteka ta napisana jest w języku C / C++, aby z niej korzystać w Javie konieczne jest zaimportowanie natywnych elementów — na szczęście LWJGL robi to za nas i nie musimy się tym martwić, nie będziemy też zgłębiać się w szczegóły jak taki mechanizm działa.
Konkurencyjną do OpenGL technologią jest Direct3D — element biblioteki DirectX oferowanej przez firmę Microsoft. Z uwagi na lepsze wsparcie na systemach poza Windowsem, OpenGL jest bardziej popularnym rozwiązaniem.
Obecnie istnieje kilka ‘wariantów’ OpenGL, m.in. OpenGL ES, który jest głównym silnikiem graficznym platformy Android i iOS . Na jego podstawie powstał też standard WebGL, który oferuje podobne możliwości, ale w ramach przeglądarek internetowych (obsługujących HTML5, którego to jest częścią). Znajomość zasad pracy z OpenGL pozwoli Ci w przyszłości łatwiej spróbować swoich sił np. z tworzeniem gier mobilnych czy takich, które działają w przeglądarce internetowej.
Zastrzeżenie
Nasza gra, którą będziemy pokazywać na screenach w trakcie tej serii, będzie się różniła od tego, co zobaczysz uruchamiając przykład czy pisząc samodzielnie podążając za kursem. Powód tego jest prozaiczny — nie jesteśmy grafikami i ‘ładne’ grafiki po prostu kupiliśmy, licencja jednak nie pozwala nam dzielić się tymi grafikami z Tobą. Dlatego w materiałach do pobrania i na repozytorium znajdziesz mniej estetyczne grafiki, które pochodzą z darmowych zestawów. Nie martw się jednak — na końcu tej lekcji znajdziesz przykładowe linki, pod którymi możesz kupić ładny zestaw grafik. Za nasze zapłaciliśmy w sumie ok. 60zł — także nie jest to majątek, a możemy dopasować grę do ulubionej postaci naszego dziecka/rodzeństwa/partnera/rodziny itp. Oczywiście nie jest to konieczne i można także używać bezpłatnych elementów lub też stworzyć własne — ograniczeniem jest tutaj tylko Twoja wyobraźnia :)
Jak zapewne zauważysz w kolejnych częściach, kod będzie pisany ‘po angielsku’ — nazwy klas i metod będziemy bazowali na języku angielskim. Powód jest prozaiczny — jak już wspominaliśmy planujemy uruchomić anglojęzyczną wersję bloga. I choć ostatnio nie mamy na to zbyt wiele czasu, posiadanie kodów źródłowych w tym języku znacznie ułatwi nam tłumaczenie treści w przyszłości :)
Jak pisze się gry
Zacznijmy od wstępu teoretycznego — czyli jak ‘działa’ gra. Różnic w stosunku do ‘standardowych’ aplikacji jest wiele, ale nie jest to też magia ;)
Rysowanie — wyświetlamy grafikę
Przede wszystkim wyświetlanie — gry bardzo często intensywnie korzystają z procesora czy pamięci, czasem spowalniając cały komputer — objawia się to ‘poklatkową’ grafiką — przykładowo ekran odświeża się co najwyżej kilkanaście razy na minutę. Jak zapewne nieraz widziałaś, kiedy ‘normalna’ aplikacja się ‘zatnie’, widać kolejność, w jakiej pojawiają się czy są modyfikowane elementy. Podobnie wygląda to na stronach internetowych, które wczytują się powoli. Dlaczego w grach wygląda to inaczej? Dlatego, że stosowany jest tutaj pewien trick.
Przede wszystkim w przeciwieństwie do standardowych aplikacji za każdym razem scena przerysowywana jest od nowa — dzieje się to kilkadziesiąt razy na sekundę (co najmniej 30 razy, aby animacja była płynna), i liczbę tą często opisuje się jako FPS — frames per second. Im wydajniejszy komputer, tym wskaźnik ten będzie większy. Co więcej — liczba ta się zmienia, w zależności od dostępnych mocy obliczeniowych w danym momencie. Jak więc gra ‘wie’ co wyświetlić w danej klatce, aby np. chodzenie odbywało się zawsze z tą samą prędkością? Otóż wszelkie akcje w grze (takie jak ruch, wrogowie itp) są przechowywani w odniesieniu do czasu rzeczywistego — czyli np. ilości milisekund od uruchomienia gry. Dzięki temu gra wie, że skok czy pojedynczy ruch zajmuje określoną ilość czasu i powoduje przesunięcie o określoną ilość jednostek w grze — wiedząc jaki jest ‘czas’ w przyjętej skali odniesienia w momencie rysowania sceny, gra może precyzyjnie określić w jakiej pozycji powinien być gracz, wrogowie itp.
Zastanawiasz się teraz pewnie dlaczego, nawet jeśli komputer spowalnia, nie ‘widać’ tego przerysowywania. Otóż zastosowanie tutaj ma kolejny sprytny trick. Zamiast najprostszego cyklu -> wyczyść ekran -> narysuj od nowa -> powtórz, komputer trzyma w pamięci dwa ‘ekrany’ (nazywa się to formalnie ramki — w języku angielskim frames; realnie jest ich więcej niż dwie, ale zasada pozostaje ta sama). Jedna jest wyświetlana, natomiast drugiej używamy do rysowania. Kiedy ta ramka jest gotowa i w pełni narysowana, instruujemy kartę graficzną ‘zamień je ze sobą’ i powtarzamy operacje. Operacja ‘zamień’ wymaga jedynie przepisania obszaru pamięci i wykonuje się bardzo szybko — w maksymalnie kilkadziesiąt cykli procesora (czyli ok. jednej miliardowej części sekundy na współczesnym sprzęcie), dzięki czemu nie widać efektu ‘rysowania’.
Obsługa klawiatury, myszki itp
Klawiaturę można obsługiwać na dwa sposoby — albo w osobnym wątku, czekając na naciśnięcie klawisza, albo odczytywać bufor klawiatury w momencie przerysowywania ekranu. Będziemy korzystać z tego drugiego podejścia — nie jest nam potrzebny wątek tylko do obsługi wejścia, co pozwoli nam nieco uprościć nasz kod. Tryb ten jest też wspierany przez LWJGL, co także nieco ułatwi.
W grze założymy proste sterowanie — strzałki do poruszania się, spacja do wykonywania akcji i enter oraz escape do poruszania się w menu.
Zasoby gry
W ramach wyjaśnienia dlaczego pewne rzeczy będziemy implementowali w ten a nie inny sposób — a konkretnie dlaczego będziemy starali się wczytać wszystkie pliki graficzne i dźwiękowe zanim grę w ogóle wyświetlimy. Otóż operacje na plikach są najdroższe, jakie można wykonać. Aby to zobrazować — wczytanie jednego pliku graficznego to załóżmy 100 operacji procesora (trochę nieefektywnie, ale niech będzie). Przy współczesnych procesorach zajmie to teoretycznie jedną stumilionową część sekundy, czyli jakieś 10 nanosekund. W przypadku dysków tradycyjnych, samo ułożenie głowicy w miejscu do odczytu zajmuje średnio 10–15 ms, czyli ponad 10 000 nanosekund. Jeśli przyjmiemy, że dla płynnej animacji potrzebujemy wygenerować co najmniej 30 klatek na sekundę, oznacza to że mamy ok. 30ms na wygenerowanie jednej — w takiej sytuacji wczytanie więcej niż jednego pliku stanie się zauważalne dla płynności animacji. I to przy założeniu, że żadna inna aplikacja nie korzysta z dysku w danym momencie.
Oczywiście są szybsze dyski, są także dyski SSD, które jeszcze bardziej skracają ten czas, ale w dalszym ciągu dostęp do pamięci RAM jest o rząd wielości szybszy od dostępu do jakiegokolwiek dysku.
Z tego powodu będziemy wczytywać maksymalnie wiele elementów do pamięci RAM, aby wykorzystywać je później bez zbędnej zwłoki.
Podsumowanie
Wiesz już mniej więcej jak będzie wyglądało tworzenie gier, i z jakich technologii będziemy korzystać. Wprawdzie jeszcze nie napisaliśmy ani jednej linijki kodu, zabierzemy się za to już w kolejnej lekcji. Póki co warto zapoznać się z technologiami, których będziemy używać, wybrać grafiki do Twojej gry lub wymyślić własną fabułę, którą zrealizujesz razem z naszym kursem!
Konkurs
Żeby było troszkę ciekawiej, mamy dla Was konkurs! Do końca tygodnia (do północy z niedzieli 27.12.2015 na poniedziałek 28.12.2015) możecie zgłaszać swoje propozycje rozszerzenia do gry — np. możliwość strzelania, dodatkowe przeszkody, akcje, które można wykonywać, elementy planszy — tak naprawdę cokolwiek, co przyjdzie Ci na myśl. Pomysły będziemy oceniać pod kątem tego jak bardzo są interesujące, ale także czy są kompletne (np. proponując strzelanie opisz także czym są pociski, jak działają na otoczenie czy przeszkody, czy jest skończona czy nieskończona ilość itp). Najciekawsze odpowiedzi zaimplementujemy w grze w trakcie tego mini-kursu, a dwie odpowiedzi nagrodzimy: jedną książką o pisaniu aplikacji mobilnych na system Windows 10, a drugą książką o Scrumie.
Piszcie Wasze propozycje w komentarzach!
Zwycięzcami konkursu są Marcinho oraz anthime — gratulujemy! Będziemy się kontaktować mailowo, a Wasze pomysły zaimplementujemy w grze ;)
Zasoby
- http://opengameart.org — grafiki, ścieżki dźwiękowe itp
- http://www.newgrounds.com — bardzo duże zasoby, w szczególności muzyki (na licencji CC — do użytku niekomercyjnego)
- http://www.gameart2d.com — głównie grafiki, całkiem dobrej jakości (także w sekcji freebies)
- http://graphicriver.net — ilustracje, grafiki, obrazki itp — strona jest płatna, ale można tam trafić naprawdę na perełki (pod kątem gier, szukaj ‘sprites’ albo po prostu ‘game’)
- https://craftpix.net/freebies/ — bezpłatne i płatne elementy do gier
- https://creativemarket.com — podobna do powyższej, konkurencyjna strona, także wiele bardzo ładnych elementów w korzystnej cenie