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 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: 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<dynamic*>::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:

  1. W pliku load_unload.cpp w metodach load i unload dopisz odpowiednie linijki wczytujące postać i zwalniające po niej pamięć.
  2. 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 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ł):

Wersja podstawowa

Program powinien składać się z następujących klas:

  1. Klasa GameStep i dziedziczących po nich: Start, Battle, Riddle, Travel, Fate
  2. Klasa Heroe
  3. 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.

pl/dydaktyka/jimp2/2017/labs/dziedziczenie-ex.txt · ostatnio zmienione: 2019/06/27 15:50 (edycja zewnętrzna)
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0