====== 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.