Założenia projektu: Nowa wersja starej gry, w której kot zbiera spadające jajka. Projekt korzysta m.in. ze sterowania kotem za pomocą klawiatury, funkcji switch...
Opis projektu:
“Kot zbiera jajka” to nowa wersja (bardzo) starej gry. Scratchowy kot w kurniku łapie toczące się jajka. Jeśli uda mu się, to dostaje punkt, a jajko jest uratowane. W przypadku niepowodzenia, z jajka wykluwa się kaczuszka, która natychmiast ucieka, a kot traci jedną z 3 szans. Występuje 5 klas:
- Kot (obiekt: scratchus), który trzyma w ręce siatkę do łapania jajek. Pojawia się po uruchomieniu programu. Sterujemy nim za pomocą klawiszy “a,z,k,m”, ustawiając kota na wylocie jednej z 4 grzęd.
- Jajko (obiekty bez nazwy), które pojawia się na początku jednej z 4 grzęd. O miejscu pojawienia się jajka świadczy parametr losowany w klasie Kurnik. Jajko stacza się po grzędzie, obracając się. Na końcu sprawdza, czy jest tam kot. Wpada do siatki lub spada i zamienia się w kaczuszkę, która ucieka.
- Kurnik - podklasa Świata, w którym dzieje się wszystko. Odpowiada za pojawianie się w nim obiektów. Sprawdza, ile jest obiektów na ekranie i dodaje jajko w losowym miejscu.
Realizacja: Tworzenie klas
Klasa Kurnik
Zacznijmy od przygotowania sceny. Klikamy prawym przyciskiem myszy w klasę World i wybieramy Nową Podklasę “New subclass...”. Tworzymy klasę Kurnik. Wybieramy jasne tło np. bricks2.
Klasa Grzeda
Tworzymy klasę Grzeda (w nadklasie Actor), przypisując jej obrazek (prostokąt 275x10 pikseli), który wcześniej przygotowaliśmy. Obrazek ten importujemy klikając przycisk “Import from file...” i wskazując lokalizację naszego pliku.
Klasa Kot
Tworzymy klasę Kot (w nadklasie Actor), przypisując jej obrazek, który wcześniej przygotowaliśmy. Wgrywamy jak wyżej.
Klasa Jajko
Tworzymy klasę Jajko (w nadklasie Actor), przypisując jej obrazek, który wcześniej przygotowaliśmy. Wgrywamy jak wyżej.
Klasa Licznik
Tworzymy klasę Licznik (w nadklasie Actor), nie przypisując jej obrazka, gdyż pojawi się tutaj obraz Greenfoota - napis.
Realizacja: Tworzenie obiektów oraz metod
Klasa Kurnik
Skoro utworzyliśmy klasy, czas na stworzenie konkretnych obiektów i umieszczenie ich w naszym świecie. W klasie Kurnik na wstępie deklarujemy dwa obiekty:
Licznik napis; Kot scratchus;
Następnie w konstruktorze tworzymy nowe obiekty i umieszczamy je na ekranie: Kota scratchusia oraz 4 grzędy, które od razu obracamy o odpowiedni kąt. Tworzymy też napis klasy Licznik oraz ustawiamy prędkość działania programu na 20:
public Kurnik() { super(800, 600, 1); scratchus = new Kot(); addObject(scratchus, 400, 500); Grzeda grzeda1 = new Grzeda(); addObject(grzeda1, 685, 150); grzeda1.setRotation(-30); Grzeda grzeda2 = new Grzeda(); addObject(grzeda2, 685, 400); grzeda2.setRotation(-30); Grzeda grzeda3 = new Grzeda(); addObject(grzeda3, 115, 150); grzeda3.setRotation(30); Grzeda grzeda4 = new Grzeda(); addObject(grzeda4, 115, 400); grzeda4.setRotation(30); napis = new Licznik(); addObject(napis, 400, 50); Greenfoot.setSpeed(20);}
Po skompilowaniu powinien pojawić się taki widok:
Zadaniem Kurnika będzie także zadbanie o to, aby na świecie były jajka oraz generowanie ich. Jednym z rozwiązań może być sprawdzanie, ile aktualnie obiektów jest na świecie. Na pewno zawsze znajduje się tam kot, 4 grzędy i napis (łącznie 6 obiektów). W związku z tym, jeśli liczba obiektów jest mniejsza od 7 należy wygenerować nowe jajko za pomocą metody dodajJajko(). Ponieważ sprawdzanie musi dokonywać się nieustannie, umieszczamy je w pętli - metodzie act:
public void act(){ if(numberOfObjects()<7) dodajJajko(); }
Co będzie robiła metoda dodajJajko()? Najpierw wylosuje jedną z czterech liczb od 0 do 3 za pomocą wbudowanej metody
Greenfoot.getRandomNumber(4)
gdzie 4 oznacza: losuj liczbę całkowitą od 0 do 4-1 Następnie w zależności od wartości wylosowanej liczby umieści ją w odpowiednim miejscu. Przykładowo:
0 - prawa góra
1 - prawa dół
2 - lewa dół
3 - lewa góra
Skorzystamy z funkcji
switch(liczba naturalna)
case 0: //jeżeli tą liczbą jest zero, zrób to:
coś do wykonania;
break; //przerwij sprawdzanie, jeśli to było zero
Ponieważ wylosowane miejsce będzie miało wpływ na dalsze poruszanie się jajka, przekazujemy tę pozycję do obiektu za pomocą parametru. Stąd ciało metody wygląda następująco:
public void dodajJajko(){ int gdzieJajko = Greenfoot.getRandomNumber(4); switch (gdzieJajko) { case 0: addObject(new Jajko(0), 775, 55); break; case 1: addObject(new Jajko(1), 775, 305); break; case 2: addObject(new Jajko(2), 25, 305); break; case 3: addObject(new Jajko(3), 25, 55); break; } }
Klasa Kot
Głównym bohaterem jest Kot, więc przejdźmy do zaprogramowania jego postępowania. Zadaniem Kota będzie łapanie jajek w siatkę, czyli pojawienie się w odpowiednim miejscu i odwrócenie się w odpowiednią stronę. Ponieważ informacja o aktualnym położeniu będzie nam potrzebna w innych klasach, musimy zadeklarować ją na początku
int gdzie;
Następnie w każdym momencie powinniśmy sprawdzić czy gracz nacisnął klawisz w celu przemieszczenia Kota. Jeśli został naciśnięty jeden z wybranych przycisków, kot powinien ustawić wartość zmiennej gdzie na odpowiednią wartość (adekwatnie do oznaczeń użytych przy Jajku), umieścić kota w odpowiednim miejscu oraz obrócić go w odpowiednią stronę.
Nasłuchiwanie, czy przycisk został naciśnięty, umieścimy w metodzie act, gdyż ma się to dokonywać nieustannie. Do sprawdzenia służy metoda Greenefoota isKeyDown("nazwa_klawisza"), która zwraca wartość true, w przypadku naciśnięcia przycisku. Efekt obracania można uzyskać za pomocą stworzenia symetrycznego odbicia metodą getImage().mirrorHorizontally(). Miejsca, w których ma się pojawić kot po naciśnięciu poszczególnych klawiszy, należy dobrać eksperymentalnie. Ciało metody act może wyglądać następująco:
public void act() { if(Greenfoot.isKeyDown("a")){ gdzie=3; setLocation(370,210); setImage("kot.gif"); getImage().mirrorHorizontally();} if(Greenfoot.isKeyDown("z")){ gdzie=2; setLocation(370,460); setImage("kot.gif"); getImage().mirrorHorizontally();} if(Greenfoot.isKeyDown("k")){ gdzie=0; setLocation(430,210); setImage("kot.gif");} if(Greenfoot.isKeyDown("m")){ gdzie=1; setLocation(430,460); setImage("kot.gif");}
}
Klasa Jajko
Zatem przejdźmy teraz do tworzenia programu w klasie Jajko. Zadaniem jajka, które po wygenerowaniu pojawi się w odpowiednim miejscu, będzie stoczenie się po grzędzie, na końcu sprawdzenie, czy jest tam kot z siatką. Jeśli jest, to jajko znika i zostaje naliczony punkt, a jeśli nie ma kota - jajko spada, rozbija się, zamienia w kaczuszkę, która ucieka do najbliższej (prawej/lewej) krawędzi.
Poruszanie się jajka będzie zależało od tego, z której strony ekranu się pojawiło. Jednak zawsze będzie przemieszczało się o pewną wartość w dół (zmiana współrzędnej y), w prawo/lewo (zmiana współrzędnej x) oraz obrót wokół własnego środka (wrażenia toczenia się). Wartość y będzie zawsze dodatnia - niezależnie gdzie się pojawi. Zmiana x: jeśli z lewej - wzrasta, z prawej - maleje. Obroty: z prawej - kierunek przeciwny do ruchu wskazówek, z lewej - zgodny. Kiedy mają następować ruchy? W kolejnych cyklach metody act. Można więc zaplanować, ile taktów ma trwać ruch jajka. W zerowym jajko pojawia się w miejscu startowym, w piątym jest już za grzędą i sprawdza, czy czeka tam kot, w siódmym zamienia się w kaczuszkę, która w kolejnych cyklach biegnie do krawędzi, a po dotknięciu jej, zmniejsza wartość zmiennej szansy o 1 i znika. Potrzebujemy więc kilka zmiennych, które deklarujemy na początku klasy:
int zmianaX, obrot, gdzie, n=0;
Ponieważ tworzyliśmy Jajko z parametrem np new Jajko(2), konstruktor Jajka też musi zawierać parametr:
public Jajko(int gdzie)
Jak wspomnieliśmy wcześniej, należy ustalić odpowiednie wartości (znaki) w zależności, czy jajko jest po prawej (gdzie<2) czy po lewej (gdzie=2 lub 3). Wartości zmiennych należy dobrać eksperymentalnie. Konstruktor może wyglądać tak:
public Jajko(int gdzie){ this.gdzie=gdzie; if(gdzie<2) { setRotation(-30); zmianaX = -51; obrot = -30; } else{ setRotation(30); zmianaX = 51; obrot = 30; } }
Przejdźmy do metody act. Abyśmy mogli odwoływać się do Świata i do innych klas, musimy tworzyć zmienną swiat klasy Kurnik i do niej “sprowadzić” nasz World za pomocą kodu:
Kurnik swiat = (Kurnik) getWorld();
W pierwszych czterech taktach tworzymy efekt toczenia się jajka po grzędzie, zmieniając współrzędne x i y jajka o określoną wartość i obracając o określony kąt:
if(n<5) {setLocation(getX()+zmianaX, getY()+30); turn(obrot); }
Można też, dla zwiększenia liczby jajek w trzecim takcie, dodać kolejne jajko, wywołując metodę dodajJajko w świecie, a dokładnie w klasie Kurnik:
if(n==3){swiat.dodajJajko();}
Zgodnie z ustaleniami w piątym takcie sprawdzamy, czy kot czeka w odpowiednim miejscu na jajko, tzn. porównujemy wartość zmiennej gdzie jajka z wartością zmiennej gdzie kota. Możemy się do niej odwołać przez zmienną swiat: swiat.scratchus.gdzie
Jeśli te wartości są identyczne, dodamy punkt, wywołując metodę dodajPunkt w Liczniku (zajmiemy się tym za chwilę, więc gdybyśmy teraz skompilowali program - zaprotestuje) oraz usuniemy jajko za pomocą metody Świata removeObject(this):
else if(n==5){ if(gdzie==swiat.scratchus.gdzie){ swiat.napis.dodajPunkt(); getWorld().removeObject(this);}}
Jeżeli jajko nie zostało złapane przez kota, spada w kolejnym cyklu - zmienia y:
else if(n<7) {setLocation(getX(), getY()+50);}
Od siódmego taktu zamiast jajka jest kaczuszka ustawiona w prawo, co odpowiada prawym grzędom. Jednak jeśli jajko było po lewej stronie, należy obrócić ją w lewo. Następnie bez względu na stronę, pójdzie przed siebie, aż dotknie krawędzi. Wtedy wywoła w Liczniku metodę straconaSzansa (stracimy 1 szansę) i kaczuszka zniknie z ekranu.
else{setRotation(0); setImage("kaczka.png"); if(obrot>0){ setRotation(180); getImage().mirrorVertically(); } move(50); if(isAtEdge()){ swiat.napis.straconaSzansa(); getWorld().removeObject(this); } }
Ostatnią czynnością - aby takty były naliczane - jest dodanie na końcu metody act zwiększanie wartości zmiennej n o 1:
n++;
Klasa Licznik
W klasie Jajko wywołujemy dwie metody z klasy Licznik, więc musimy jak najszybciej nadrobić zaległości. Licznik będzie wyświetlał różne informacje na górze ekranu. Zawsze, gdy będziemy chcieli wyświetlić jakiś napis, stworzymy obiekt klasy GreenfootImage, który będzie napisem.
Zmienne zawierające punkty i szanse będą używane w różnych metodach tej klasy, więc deklarujemy je na początku:
int pkt, szansa;
W konstruktorze Licznika przypisujemy tym zmiennym konkretne wartości: 0 punktów i np. 3 szanse oraz wywołujemy napis “Jestem gotowy!”. Napis tworzymy za pomocą konstruktora GreenfootImage o 4 parametrach (“Tekst do wyświetlenia”, rozmiar czcionki, kolor czcionki, kolor tła). Przypomnienie: aby użyć kolorów, musimy importować bibliotekę:
import java.awt.Color;
Kolor null oznacza tło przezroczyste. Zatem konstruktor może wyglądać tak:
public Licznik(){ GreenfootImage klikniecia = new GreenfootImage ("Jestem gotowy!", 36, Color.RED, null); setImage (klikniecia); pkt = 0; szansa = 3; }
Wcześniej wywoływaliśmy metodę dodajPunkt, której działanie ma polegać na zwiększeniu wartości punktów o 1. Może ona wyglądać tak:
public void dodajPunkt() { pkt++; }
Warto byłoby od razu pokazać te punkty graczowi. W związku z tym można w metodzie act nakazać programowi nieustanne aktualizowanie danych przez wyświetlanie bieżących wartości:
public void act()
{GreenfootImage klikniecia = new GreenfootImage ("Złapane: " + pkt +"\n Szanse: " + szansa, 36, Color.RED, null);
setImage (klikniecia);}
Drugą metodą użytą w klasie Jajko jest straconaSzansa. Jej zadaniem będzie odejmowanie szans w przypadku ucieczki kaczuszki oraz sprawdzanie, czy nie wykorzystaliśmy wszystkich szans. Jeśli tak, należy zakończyć grę i poinformować o tym gracza. Ciało metody może wyglądać tak:
public void straconaSzansa() { szansa--; if(szansa<1){ GreenfootImage klikniecia = new GreenfootImage ("Złapane: " + pkt +"\n The End :( ", 36, Color.RED, null); setImage (klikniecia); Greenfoot.stop(); } }
Klasa Grzęda
Ponieważ grzęda nie wykonuje żadnych czynności, nie tworzymy w niej kodu.
Modyfikacja: Zwiększenie tempa
Aby uatrakcyjnić grę, można zwiększać tempo gry, gdy użytkownik nabierze wprawy - to znaczy, gdy będzie zdobywał kolejne punkty. Jeśli chcemy, aby co 5 jajek tempo gry zwiększało się o 1, można w metodzie act Kurnika umieścić kod:
Greenfoot.setSpeed(20+(int)napis.pkt/5);
Czyli prędkość gry nie będzie wynosiła zgodnie z ustawieniami poczatkowymi 20, ale będzie wzrastała. napis.pkt jest odwołaniem do zmiennej pkt z obiektu napis (klasy Licznik), a (int)ułamek oznacza konwersję ułamka na liczbę całkowitą.