====== Dziedziczenie i polimorfizm -- przykłady ======
To laboratorium jest opcjonalne i zawiera przykłady mające na celu pokazanie dziedziczenia i polimorfizmu na większych przykładach.
Z racji, że nie jest to "regularne" laboratorium, nie obowiązuje ono do kolokwium, a za rozwiązanie zadań nie będą przyznawane plusy/punkty. Oczywiście w przypadku jakichkolwiek pytań czy wątpliwości zapraszam do zadawania pytań / pisania maili / przychodzenia na konsultacje! Udzielę wszelkich wyjaśnień :-)
===== Fin de Siecle =====
Jest to prosta gra platformowa na licencji GPL, która bardzo silnie bazuje na koncepcji polimorfizmu 8-). Rysunki z gry są autorstwa [[http://www.youtube.com/user/RidooAnimations|Michała Klimczyka]].
====Kompilacja i uruchomienie====
Aby skompilować grę, zainstaluj następujące pakiety:
sudo apt-get install libsdl1.2-dev libsdl-ttf2.0-dev libsdl-sound1.2-dev libsdl-mixer1.2-dev
Następnie pobierz kod źródłowy: {{http://home.agh.edu.pl/~kkutt/jimp2/findesiecle.zip|Fin De Siecle}}, rozpakuj go i skompiluj poleceniem make
Uruchom grę poleceniem ./exe
====Organizacja kodu====
Wszystkie obiekty reprezentujące jakieś byty w grze (woda, drzewa, bohater, przeciwnicy, etc.) są przechowywane w jednej liście (tak naprawdę w kilku listach w zależności od tego, czy obiekt jest dynamiczny - jak woda, czy statyczny - jak drzewo). Aby było to możliwe, wszystkie klasy muszą dziedziczyć po tej samej klasie bazowej (w tym wypadku //object// - wszystkei, //dynamic// - dynamiczne, //colisives// - generujące kolizje). W głównej pętli gry (plik //game.cpp//, metoda //game()//) lista jest przeszukiwana, obiekty są rysowane i wykonują jakieś swoje zaprogramowane czynności. Jednakże zachowania drzew, bohatera czy przeciwników muszą być inne!
Wszystkie obiekty są polimorficzne. W momencie gdy wywoływana jest pętla rysująca elementy dynamiczne obiekty (plik //game.cpp// linia 164), wywoływana jest metoda //draw// na każdym obiekcie z listy. W liście znajdują sie przeciwnicy, woda, etc. Ale dzięki polimorfizmowi, zawsze wywoływana jest odpowiednia metoda rysująca odpowiedni obiekt, mimo że jest ona wywoływana z klasy bazowej dla tych obiektów:
list::iterator it;
for(it = dynamics.begin();it != dynamics.end();it++)
(*it)->draw(screen);
====Dla chętnych ====
Dopisz nowego przeciwnika do gry, który będzie rzucał się w pościg za głównym bohaterem gdy go zobaczy. Stwórz klasę identyczną do klasy //policeman// - pamiętaj aby zaimplementować wszystkie metody potrzebne do poprawnego "funkcjonowania" przeciwnika (zamiast metody gdzie policjant rzuca pałką, napisz metodę która będzie wprowadzała Twoją postać w sprint).
Aby twoja postać została wczytana, musisz dokonać dwóch modyfikacji:
- W pliku //load_unload.cpp// w metodach //load// i //unload// dopisz odpowiednie linijki wczytujące postać i zwalniające po niej pamięć.
- W pliku z planszą gry - //gdata/level0.dat// dopisz linijkę, która będzie opisywać współrzędne Twojego bohatera na planszy. Na przykład chcą postawić postać, która ma identyfikator //myMan// na 1000 pikselu planszy licząc od lewej i na 300 pikselu licząc od dołu wpisujemy linijkę:myMan 1000 300
===== Math Evaluation =====
Jest to ewaluator wyrażeń matematycznych, którego działanie opiera się na polimorfizmie.
==== Kompilacja i uruchomienie ====
Pobierz i rozpakuj archiwum {{http://home.agh.edu.pl/~kkutt/jimp2/mathevaluation.zip|Math Evaluation}} a następnie skompiluj program poleceniem make
Uruchom program poleceniem ./exe
Istnieje możliwość podawania wyrażeń do ewaluacji jako parametrów programu, ale w tym celu trzeba odkomentować odpowiednią linijkę w funkcji //main//.
====== Ćwiczenie ======
Tekstowa gra RPG. Dla chętnych: można połączyć się w grupy dwuosobowe.
Scenariusze (ta lub inne strony, albo własny pomysł):
- [[http://www.gildiarpg.pl/adventures/|Gildia RPG]]
- [[http://www.rpgmaker.10giga.pl/?co=krypta&typ=scenariusze|RPG Maker]]
===== Wersja podstawowa =====
Program powinien składać się z następujących klas:
- Klasa //GameStep// i dziedziczących po nich: //Start, Battle, Riddle, Travel, Fate//
- Klasa //Heroe//
- Klasa //Artefact//
====GameStep====
Klasa GameStep powinna być klasą abstrakcyjną posiadającą następujące wirtualne metody czyste:
* void play(Heroe&)
* GameStep* getNext()
Klasy dziedziczące po GameStep powinny:
* Start - po wywołaniu //play// na bohaterze, losować jego atrybuty (punkty zdrowia, sila, zrecznosc), po wywolaniu //getNext//, powinna być losowo zwrócony jeden z obiektów GameStep.
* Battle - po wywołaniu //play// powinna rozpocząć się walka. Obiekt klasy //Battle// posiada także atrybuty takie jak punkty zdrowia, sila i zrecznosc. Walka toczy się dopóki przeciwnik, albo bohater nie stracą wszystkich punktów życia. Obliczanie strat w punktach życia dla stron może odbywać się na przykład według takiego wzoru: sila*rand()%zrecznosc
* Travel - po wywołaniu //play// na bohaterze, powinno pojawić się pytanie, czy chce wyruszyć w niespokojne okolice, gdzie czeka go walka, czy też woli podróżować po bezpiecznej drodze. W zależności od wyboru, metoda //getNext// zwracać będzie albo //Fate// - gdy wybierze podróż, albo //Battle// gdy wybierze walkę.
* Fate - Może oznaczać szczęście albo pecha - losowane //randomowo//. W przypadku szczęścia bohater znajduje eliksir, albo artefakt, który zwiększa jego atrybuty. W przypadku pecha ma 20% szans na utratę swoich wcześniejszych artefaktów.a
* Riddle - Tylko po bitwach. Zagadka, której rozwiązanie skutkuje otrzymaniem jednej magicznej runy, lub całkowitym uleczeniem gracza. Gracz wygrywa gdy zbierze 7 magicznych run. Przegrywa, gdy straci wszystkie punkty życia.
====Artefact====
Klasa //Artefact// powinna być klasą abstrakcyjną, po której dziedziczyć będą różne artefakty. Dodające siłę, zręczność, czy punkty życia. Bohater (czyli obiekt klasy //Heroe//) powinien posiadać listę artefaktów. **Zaprojektuj sam jak powinna wyglądać ta klasa**.
====Heroe====
Klasa //Heroe// powinna reprezentować bohatera. Powinna posiadać listę artefaktów, która to lista będzie wymagana do obliczenia aktualnej siły, zręczności i punktów życia bohatera. Liczba magicznych run może być zwyczajnym polem typu //integer// (chyba że ktoś wpadnie na pomysł, że magiczne runy też dodają jakieś atrybuty).
Resztę klasy zaprojektuj według uznania.
====Fabuła====
Można pokusić się o wprowadzenie fabuły do gry, poprzez ustalenie jakichś zbiorów z których są losowane walki, zagadki itp. Na przykład jeśli bohater posiada 1 magiczną runę, to losuj ze zbioru "A", jeśli 2 to ze zbioru "B", itd. (W takim wypadku metoda //getNext// musiałaby pobierać jako parametr obiekt bohatera w celu ustalenia w jakiej fazie gry się znajduje).
===== Wersja zaawansowana =====
Rozbudowa polegałaby na pewno na dodaniu mapy, broni, questów.