--------------------------------------------------------------- | Projekt projektu zaliczeniowego z Programowania Obiektowego | --------------------------------------------------------------- Marcin Pilipczuk, 2004. 0.1. Historia zmian ------------------- - 23.11. Wersja 0.1.0 - 28.11. Wersja 1.0.0 - dopisanie brakujących fragmentów. - 12.12. Wersja 1.1.0 - poprawienie stosownie do uwag 0.2. Skrót ---------- Dokument ten zawiera projekt interfejsu graficznego oraz projekt hierarchii klas oraz podstawowych metod rozumianych przez klasy dla projektu zaliczeniowego z PO - gra w rycerzy chodzących po labiryncie. 0.3. Notacja ------------ Dokument składa się z dużych rozdziałów oraz podrozdziałów oznaczonych odpowiednio dużymi i małymi literami alfabetu. Z tymi oznaczeniami przeplata się oznaczenie projektu hierarchii klas - każda klasa ma swój numer w postacii ciągu liczb, przy czym np. klasa X.Y.Z. jest podklasą klasy X.Y., która jest podklasą klasy X., która to jest podklasą klasy Object. W dokumencie klasy są ułożone leksykograficznie względem numerów. A. Projekt interfejsu graficznego ================================= Gra odbywa się w trzech małych okienkach. Jedno, zwane później Menu, jest małym oknem zawierającym tylko menu gry, umieszczonym w górnej części ekranu (wymiary ok. 200x50). Poniżej, podczas trwania rozgrywki, są dwa okna opisujące rozgrywkę, o wysokości ok. 600 pikseli. Jedno, o szerokości ok. 120 pikseli, podaje aktualna informację o stanie drużyny, drugie zaś, kwadratowe ok. 600x600, pokazuje mapę. A.a. Menu --------- Menu jest standardowym rozwijanym menu, zajmującym pasek o szerokości ok. 30 pikseli na górze okna. Zawiera następujące kategorie, a w nich możliwości: * Program - ogólnie sterowanie programem. - Nowa gra - pojawia się okno pozwalające wybrać mapę i rozpoczyna nową grę. - Restart gry - restart gry na tej samej mapie co jest - Poddaj - poddaje aktualna grę. - Zapisz grę - zapisuje grę. - Wczytaj grę - wczytuje zapisaną grę. - Koniec - kończy działanie programu. * Rozkazy - rozkazy do wydania podwładnym - lista pięciu rycerzy, do wybrania, który teraz ma się ruszać - możliwe ruchy do wyboru: lewo, prawo, dół, góra, aktualnym rycerzem - spauzuj turę * Opcje - kilka opcji co do gry (checkboxy) (mała modyfikacja zasad) - czy widać, kiedy się odnowi mina/mur/dziura. - czy widać, kiedy do magazynu przybędzie nowy surowiec. - czy skoczek może ruszać się o jedno pole. * Pomoc - zasady gry - wyświetla plik z zasadami gry - o programie - okienko z nr wersji itp. A.b. Informacje o rycerzach --------------------------- Pasek informacji o rycerzach jest pasem o szerokości 120 pikseli standardowo ustawionym z lewej strony ekranu. Na górze paska jest pięć obrazków obrazujących kolejnych rycerzy. Jest to logo rycerza, pokazujące co to za tym rycerza (jakaś bitmapa), oprócz tego ew. informacja o liczbie zębów lub liczbie cegieł dostępnych, oraz podświetlony będzie rycerz aktywny (zaznaczony). Rycerze są zastępowani trupimi czaszkami lub znaczkiem smoka, jeśli umrą lub dotrą do legowiska. Kliknięcie na rycerza powoduje jego podświetlenie i scentrowanie mapy na zaznaczonym rycerzu. Poniżej obrazków rycerzy znajduje się informacja tekstowa o zaznaczonym rycerzu: typ słownie, ilość dostępnych surowców (zęby i cegły) oraz pozycja na planszy. Poniżej są napisane informacje co do pola zaznaczonego prawym przyciskiem myszy (patrz plansza). Jest również na dole informacja liczbowa, ilu rycerzy żyje, ilu jest w leżu smoka i ilu jeszcze musi dojść do końca, oraz numer tury. A.c. Plansza ------------ Okienko planszy, ma rozmiar ok. 600x600 pikseli. Jest to przesuwany kawałek planszy o stałej skali (jedno pole ma wymiar 50x50 pikseli), które można przesuwać w następujący sposób (moim zdaniem jest to wygodniejsze od suwaków): w momencie kliknięcia na pole prawym przyciskiem myszy, plansza centruje się na tym polu oraz z okienku informacyjnym wypisuje się informacja co do tego pola. Pola pola rysują się za pomocą bitmap, z ew. naniesionym na to liczbami odpowiadającymi informacjom - wielkość dziury czy czas odnowienia się pola na planszy. Na polach gdzie są rycerze są narysowani rycerze. Kliknięcie na pole prawym przyciskiem myszy powoduje scentrowanie planszy na tym polu oraz wypisanie informacji o polu w okienku informacyjnym. Kliknięcie na rycerza powoduje jego zaznaczenie. Zaznaczony rycerz ma narysowane koło siebie kropki. Kliknięcie na kropkę powoduje wykonanie ruchu. Kropki mają różne kolory, w zależności od skutku ruchu w tym momencie: - zielony - można iść; - żółty - można iść, ale stracimy surowca; - niebieski - tam jest teleport, nie wiemy co się stanie; - szary - nie widzimy tego pola (w przypadku skoczka), nie wiadomo co się stanie; - czerwony - nie można tam iść; - czarny - można tam iść, ale rycerz zginie. A.d. Inne zabawki ----------------- Okna otwarcia nowej gry, zapisu i wczytania gry otwierają okienko wyboru pliku. Wyjście z gry, restart, nowa gra, wczytanie gry, wymagają potwierdzenia "czy na pewno chcesz opuścić tą grę?" W momencie wygranej i przegranej pojawia się odpowiednie okienko informujące. Gra uruchamiana jest poleceniam "Gra graj". Pojawia się wówczas samo menu, z którego można rozpocząć nową grę. B. Hierarchia klas ================== Podstawową klasą jest klasa Gra, której skonstruowanie powoduje uruchomienie gry. Klasa Gra tworzy dla każdej nowej gry klasę Rozgrywka. Poniżej znajduje się sama hierarchia klas - same nazwy, z pominięciem klas służąych do wizualizacji (tez Gra jest taką klasą). 1. Rozgrywka 2. Plansza 3. ZasadyGry 4. ZadadaGry 5. Punkt 5.1. Pole 5.1.1. Mur 5.1.1.1. PozaPlanszą 5.1.2. Leże 5.1.3. Respawning 5.1.3.1. Zjadalny 5.1.3.2. Mina 5.1.3.3. Dziura 5.1.4. Teleport 5.1.5. Magazyn 5.1.5.1. Dentysta 5.1.5.2. Cegielnia 6. Rycerz 6.1. Surowcowy 6.1.1. Zębacz 6.1.2. Budowniczy 6.2. Skoczek 7. Efekt 7.1. NieMozna 7.2. Mozna 7.3. StrataSurowcow 7.4. Teleport 7.5. Smierc 8. Druzyna 9. Kierunek 9.1. Góra 9.2. Dół 9.3. Lewo 9.4. Prawo 10. LicznikTur Poniżej zaś szczegółowszy opis każdej klasy, wraz z podstawowymi zmiennymi instancyjnymi oraz rozumianymi komunikatami. 1. Rozgrywka ------------ Jest to ogólna klasa do obsługi rozgrywki. Posiada zmienne instancyjne: * plansza typu Plansza * druzyna typu Druzyna * ltur typu LicznikTur. * zaznaczone_pole typu Pole - wskaźnik na aktualnie zaznaczone prawym przyciskiem pole * startowe typu Pole - pole startowe. Posiada następujące ważne metody do grania (poza ew. potrzebnymi akcesorami) czyKoniec, czyPrzegrana, czyWygrana - pyta się drużyny o stan gry koniec, przegrana, wygrana - kończy grę z ew. komunikatami. start - rusza wczytaną nową grę (tj wykonuje pierwszą turę) nowaTura - kończy starą turę, zaczyna nową: wysyła polom komunikat aktualizuj, sprawdza, czy gra się już nie skończyła i rysuje planszę. oraz konstruktor czytający nową grę (wczytywanie zapisanej gry odbywa się przez binaryStoreOn: i binaryReadFrom:). 2. Plansza ---------- Plansza jest tylko obudową do zbioru pól, reprezentowanego przez zmienną pola (tablica tablic pól). Posiada zmienną rozmiar typu Punkt. Potrafi się zainicjować konstruktorem new: plik_z_mapą, gdzie plik_z_mapą jest typu FileStream. Posiada akcesor do pól: at: x at: y oraz at: aPunkt (który zwraca PozaPlansza, jeśli jest poza planszą). 3. ZasadyGry ------------- ZasadyGry reprezentuje zbiór zasad stosowanych w grze (opisanych w odpowienim menu). Posiada jedną zmienną zasady, która jest SortedCollection-em. Są to zasady. Rozumie komunikaty: - zasady - zwraca zasady (do przeglądania) - nowa: zasada - dodaje nową zasadę - zasada: - zwraca wartosc logiczna odpowiedniej zasady Posiada też konstruktor, który tworzy wbudowany, standardowy zbiór zasad. 4. ZasadaGry ------------- Para nazwa zasady oraz wartość logiczna czy zasada jest stosowana. Posiada akcesory wartosc i tresc oraz wartosc: nowaWartosc. 5. Punkt -------- Jest to klasa uzywana tez w innych obiektach (np. plansza), reprezentuje pare liczb calkowitych (x,y) wraz z komunikatami dostepu do tych zmiennych: x,y,x:,y: oraz stosownym konstruktorem new:new:. 5.1. Pole Pole reprezentuje pojedyncze pole na planszy. Pole ma, poza zmiennymi x i y (pozycja pola), posiada zmienną rycerz - wskazuje na ewentualnego rycerza na tym polu, widzianoCie - czy była widziana w czasie gry. Ma też wskaźnik do całej planszy - plansza, oraz do licznika tur - ltur. Rozumie ono komunikaty (większość z nich jest przeciążanych w podklasach, by osiągnąć odpowiedni efekt): - aktualizuj - pole sprawdza, czy się np. nie odnawia, nie wyprodukował się nowy surowiec itp. - chceWejsc: rycerz zkierunku: kierunek - sprawdza, czy rycerz moze wejsc na to pole, zwraca stosowny obiekt typu Efekt. W razie potrzeby Wysyła do rycerza odpowiednie komunikaty, np. czyZamurujesz. - wchodzi: rycerz - rycerz wchodzi na to pole, pole dokonuje stosownych modyfikacji rycerza (np. wysłanie komunikatu "umierasz" lub "zuzytoCegly: x"). Zakłada się, że rycerz moze wejsc na pole. - zszedl - rycerz zszedl z pola - widzianoCie - odznacza czyWidziana na true. - sąsiad: kierunek - zwraca pole będące sąsiadem w określonym kierunku. - eksploduj - obok wybuchła mina. zabij rycerza, jeśli jest, ew. zniszcz mur. Ponizsze metody są odpowiednio przeciążane w poniższych podklasach, zależnie od zachowania opisanego w specyfikacji gry. 5.1.1. Mur Mur zwraca na próby wejścia odpowiedź NieMożna. 5.1.1.1. PozaPlanszą Zachowuje się tak samo jak Mur, ale ma inną bitmapę. 5.1.2. Leże Zmienne instancyjne: ilerycerzy. W momencie wejścia rycerza, wysyła mu kominikat wygrałeś i zwiększa licznik. 5.1.3. Respawning Obrazuje pole odnawiające się co 20 tur. Posiada zmienne instancyjne flaga oraz tura_oflagowania (oznaczające odpowiednio, czy zostało użyte i w której turze), przeciążony komunikat "aktualizuj" oraz metodę "oflaguj" oznaczającą zużycie pola. 5.1.3.1. Zjadalny Przeciążona odpowiednio metoda chceWejść:zkierunku: oraz wchodzi:, zużywająca u wchodzącego ząb, jeśli mur nie jest jeszcze zjedzony. 5.1.3.2. Mina Przeciążona odpowiednio metoda chceWejść:zkierunku: oraz wchodzi:. Metoda wchodzi, w razie aktywnej miny, wysyła do siebie komunikat wybuchnij. Komunikat wybuchnij powoduje wysłanie komunikatu eksploduj do siebie i sąsiadów. 5.1.3.3. Dziura Podobnie jak Zjadalny, ma przeciążone metody chceWejść:zkierunku: oraz wchodzi:. 5.1.4. Teleport Zmienne instancyjne: dokad (typu Pole). Przeciążone metody chceWejsć:zkierunku: oraz wchodzi:. Wchodzi: sprawdza docelowe pole, czy jest wolne, i w razie czego teleportuje. chceWejść zwraca zawsze BędzieTeleport. 5.1.5. Magazyn Zmienne instancyjne: rozmiar, aktualna_ilosc, tura_poczatku_produkcji. Przeciążona metoda aktualizuj (produkująca nowy surowiec, jeśli jest taka potrzeba) oraz metoda zaopatrzaSię: rycerz, powodująca zaopatrzenie rycerza w surowiec. 5.1.5.1. Dentysta Przeciążona metoda wchodzi:, pyta się rycerza chceszZeby (tylko Zjadacz zwraca true) i wywołuje w razie czego zaopatrzaSię: 5.1.5.2. Cegielnia Przeciążona metoda wchodzi:, pyta się rycerza chceszCegły (tylko Budowniczy zwraca true) i wywołuje w razie czego zaopatrzaSię: 6. Rycerz --------- Rycerz jest dość ubogą klasą, nadzór nad nim i operacje wykonuje Pole. Rycerz wie, czy jest żywy czy martwy (zmienna instancyjna czyZyje), czy jest w leżu smoka (czyWygrał) oraz czy jest na planszy (czyNaPlanszy). Posiada też wskaźnik na pole, gdzie jest (pole), oraz który jest w kolejności (aby móc siebie narysować w dobrym miejscu na okienku informacyjnym). Rozumie komunikaty (część z nich jest odpowienio przeciążona w podklasach). - umierasz - zmienia flagę czyZyje na false. - wygrales - zmienia flagę czyWygrał na true. - naplanszy - zmienia flagę czyNaPlanszy na true. - czyWszedl, czyWygral, CzyZyje, czyGit - zwraca odpowiednio: czy jest na planszy, czy jest w leżu smoka, czy żyje, oraz czy jest na planszy, nie wygrał i czy żyje. - chceszCegły, chceszZeby - czy chce nabrać cegieł/zębów w magazynie. - czyZamurujesz: wielkoscDziury, czyZjadasz - czy rycerz jest w stanie zamurować dziurę / zjeść mur. - aktualizujSurowiec: ile_dostępne - nabiera surowca, standardowo zwraca że wziął 0. - naPole: pole - zmienia adres pola. Nie wykonuje żadnych operacji w związku z tym - wszystko mu rozkazuje Pole, tylko sąsiadom pola wysyła "widzianoCie". - idzNaPole: pole - złożona funkcja ruszania się: rycerz wpierw opuszcza swoje pole, następnie wysyła kandydatowi, że "wchodzi". Obie powyzsze metody zakladaja, ze rycerz moze wejsc na to pole (beda one wysylane przez komunikat typu Efekt, ktory wie, czy moze) - sasiedzi - zwraca OrderedCollection sąsiadów rycerza (standardowo sąsiedzi pola). 6.1. Surowcowy Posiada zmienne instancyjne: ilośćSurowca i maxSurowca, oraz komunikaty: zużyj: oraz przeciążone aktualizujSurowiec:. zużyj: zużywa odpowiednią ilość surowca, aktualizujSurowiec: ile_dostępne, dopełna o min (ile_dostępne, maxSurowca - iloscSurowca) i zwraca, ile zabrał. 6.1.1. Zębacz Przeciążony komunikat czyZjadasz oraz chceszZeby. Dodany komunikat zjadłeś (= zużyjSurowca: 1) 6.1.2. Budowniczy Przeciążony komunikat czyZamurujesz: oraz chceszCegly. 6.2. Skoczek Przeciążona metoda sąsiedzi. 7. Efekt -------- Efekt jest klasą reprezentującą efekt, gdy rycerz wejdzie na jakieś pole. Posiada zmienną instancyjną pole - odnoszącą się do swojego pola docelowego, oraz kierunek - w którą stronę chciano iść, oraz kolorRysunku - kolor do rysowania, jak również rycerz - rycerz, który chciał wchodzić. Rozumie komunikaty: - czyMoznaWejsc - ogólnie True, chyba że przeciążone (w NieMozna). - wykonanoCie - wywolywana, jak ktos kliknie na kropke odpowiadajaca efektowi (wykona ruch). Jesli nie mozna wejsc, nic nie robi, w przeciwnym wypadku wysyła rycerzowi kominikat idzNaPole:wturze:. Poniższe podklasy mają zmieniony kolorRysowania w czasie inicjacji oraz NieMozna ma przeciążone czyMoznaWejsc. 7.1. NieMozna 7.2. Mozna 7.3. StrataSurowcow 7.4. Teleport 7.5. Smierc 8. Druzyna ----------- Drużyna to klasa trzymająca wszystkich rycerzy w grze. Posiada zmienne instancyjne: - rycerze - tablica piecioelementowa rycerzy grających - aktywny - liczba z przedziału [1..5], mówiąca, który rycerz jest aktywnym rycerzem. - ltur - wskaznik na licznik tur. - ilepotrzebadowygrania - liczba, mówiąca, ile rycerzy musi się znaleźć w leżu smoka. Rozumie ona komunikaty: - iluGit/iluWygralo/iluZyje - ilu rycerzy zyje, jest na planszy i nie u smoka, ilu jest u smoka i ilu zyje - pierwszyCoWszedl, pierwszyCoNieWszedl - metody zwracające pierwszego w kolejności rycerza który (nie) jest na planszy (i jest żywy i nie u smoka). - zaznaczony - zwraca zaznaczonego rycerza - zaznaczInt: x - zaznacza rycerza o numerze x; zaznacz: r - zaznacza rycerza r. - czyWygrana, czyPrzegrana - sprawdzają, czy można coś powiedzieć o wygranej, przegranej. - aktualizujZaznaczonego - jeśli zaznaczony nie jest funkcjonalny na planszy, zaznacza pierwszego rycerza na planszy. - czytajZPliku: plik - czyta druzyne z pliku mapy. 9. Kierunek ------------ Kierunek nie ma zmiennych instancyjnych, reprezentuje kierunek ruchu. Jest to po prostu użyteczne, uczytelnia kod. Rozumie komunikaty: - od: punkt - zwraca punkt będący w swoim kierunku od argumentu Poniższe podklasy reprezentują odpowiednie kierunki. 9.1. Góra 9.2. Dół 9.3. Lewo 9.4. Prawo 9.5. Specjalny Specjalny kierunek ruchu, odnoszący się do: pojawiania się na planszy i teleportu. 10. LicznikTur -------------- Prosta klasa zliczająca: ma zmienną tura, z akcesorem i metodą do zwiększania.