Licznik Kliknięć

Z Zasoby CoderDojo
Skocz do: nawigacji, wyszukiwania

Poziom I: Klikanie przycisku

Omówienie zadania:

Na pierwszym poziomie zaprogramujemy guzik, który po kliknięciu będzie zmieniał swoje położenie, czynności które będziemy musieli wykonać to:

  1. Definicja świata - zgodnie z metodologią Greenfoot’a najpierw zaczniemy od stworzenia świata.
  2. Stworzenie i dodanie przycisku do świata.
  3. Sprawienie, aby przycisk zmieniał swoje miejsce po kliknięciu.

Realizacja zadania:

Stworzenie świata

W ogólnym rozumieniu świat w Greenfoot’cie jest miejscem, gdzie działać będą zakodowane przez nas algorytmy i gdzie będą istnieć stworzone przez nas obiekty. W rozumieniu technicznym świat jest po prostu klasą Javy, która dziedziczy z klasy World (poprzez dziedziczenie rozumiemy pewien szczególny przypadek klasy World).
Zanim przejdziemy do instrukcji krok po kroku zatrzymajmy się chwilę i spróbujmy zarysować pojęcia klasa i dziedziczenie. Zacznijmy od klasy.
Klasa w programowaniu obiektowym służy do symulacji obiektów ze świata rzeczywistego. Można powiedzieć, że programiści po wielu latach programowania stwierdzili, że pisanie coraz większych programów staje coraz trudniejsze. Potrzebowali techniki, aby je ułatwić. Stwierdzili, że dużym ułatwieniem będzie jeśli język programowania będzie naśladował relacje zachodzące w świece realnym. Wymyślili więc takie pojęcie jak klasa, za pomocą której będą mogli symulować byty z realnego świata. To tyle jeśli chodzi o ogólną definicje klasy. Teraz, aby już zupełnie rozjaśnić pojęcie skupmy się na potocznej definicji i przykładach.
Klasę w programowaniu należy traktować jako pieczątkę, stempel, formę z której tworzy się obiekty, na których następnie się pracuje. Przykładem będzie np.: klasa Samochód, która będzie opisywać samochody. Za jej pomocą stworzymy w swoim programie obiekty samochodów, które np.: będą poruszać się po drodze.
Jak więc wygląda przykładowy zapis klasy w Javie? Oto przykład klasy samochód, która nie zawiera żadnych zmiennych i metod. Poniżej, zaś przykład klasy Droga, która zawiera zmienną typu samochód (od razu też stworzyliśmy obiekt - new Samochod()):

public class Samochod {
 
}
public class Droga {
      Samochod nazwaWlasna = new Samochod();
}

Kolejnym pojęciem, które jest wykorzystywane w programowaniu obiektowym jest dziedziczenie.
Aby wyjaśnić dziedziczenie zaczniemy od przykładu. Załóżmy, że stworzyliśmy klasę Samochod, która ma 4 koła i kierownicę. Teraz chcemy stworzyć klasę Wyscigowka, która dodatkowo miałaby spoiler. Bez relacji dziedziczenia musielibyśmy w klasie Wyscigowka dodać zmienne reprezentujące koła i kierownice, co byłoby stratą czasu. Za pomocą relacji dziedziczenia możemy zapisać, że klasa Wyscigowka rozszerza (extends) klasę Samochod, dzięki temu nie będziemy musieli dodawać wyścigówce kół oraz kierownicy bo dodaliśmy je już w klasie Samochod, w kodzie mogłoby to wyglądać tak:

public class Wyscigowka extends Samochod {
        Spoiler czarnySpoiler = new Spoiler();
}

Przechodząc do instrukcji w punktach:

  1. Standardowo stwórzmy nowy projekt Greenfoot’a nazywając go LicznikKlikniec.
  2. Stwórzmy klasę o nazwie Tlo, klikając prawym klawiszem na prostokącie z napisem World i wybierając New Subclass …
    • Jako obrazek naszego tła wybierzmy plik space.jpg z kategorii background.
    • Aby potwierdzić stworzenie klasy Tlo kliknijmy na przycisk OK.
Jmk-LicznikKilikniec image02.png

Na zakończenie kliknijmy na przycisk Compile. Akcja ta przetłumaczy nam kod klasy Tlo na kod zrozumiały dla komputera.
W ten sposób stworzyliśmy pierwszą klasę w Javie. Na zakończenie tej lekcji zapamiętajmy, że klasa ta dziedziczy z klasy World. Dziedziczenie w programowaniu powstało po to, aby lepiej oddać relacje panujące w prawdziwym świecie. Przykłady relacji dziedziczenia (przykładów nigdy dość!) to np.: Owczarek Niemiecki byłby klasą dziedziczącą z klasy Pies, Młotek byłby klasą dziedziczącą z klasy Narzędzie etc.

Możliwe pytanie o klasę World - Klasa World jest gotową klasą przygotowaną przez twórców Greenfoot'a. Twórcy Greenfoot'a założyli sobie, że programista powinien zawsze stworzyć sobie przynajmniej jedną klasę, która będzie "światem jego aplikacji".

Stworzenie i dodanie przycisku do świata

W kolejnym etapie zakodujemy przycisk. Aby to zrobić będziemy musieli zapoznać się z koncepcją Actora w Greenfoot’cie. Podobnie jak w przypadku klasy World i naszych własnych światów, tak każdy stworzony przez nas aktor musi dziedziczyć po klasie Actor. No dobrze, ale kim w takim wypadku jest ów aktor? Aktor jest klasą odpowiedzialną za wykonywanie danej czynności. My jako programiści będziemy pisać klasy aktorów. W tym scenariuszu aktorem będzie przycisk a rolą jego życia będzie “bycie klikanym”. Dobrze, stwórzmy więc klasę Guzik postępując zgodnie z poniższą instrukcją:

1. Kliknijmy prawym klawiszem na ikonce Actor i wybierzmy New subclass …

  • W polu New class name wpiszmy Guzik.
  • Z kategorii symbols wybierzmy obrazek o nazwie button-green.png:
Jmk-LicznikKilikniec image01.png

2. Kliknijmy Ok a następnie Compile, aby potwierdzić stworzenie klasy Guzik.
Podsumujmy czego już dokonaliśmy. Stworzyliśmy dwie klasy: klasę świat (Tlo) i klasę aktor (Guzik). Jak na razie te dwie klasy nie są ze sobą w żaden sposób powiązane. Czas to zmienić i napisać nieco kodu. Przed tym jednak odpalmy projekt klikając na przycisk Run. Oto co powinniśmy zobaczyć:

Jmk-LicznikKilikniec image03.png

Możemy się zastanowić nad tym, gdzie podział się guzik, którego klasę stworzyliśmy? Otóż nie dodaliśmy go w żaden sposób do świata. Aby guzik był widoczny musimy dodać go do świata, dokonamy tego postępując zgodnie z poniższymi krokami:
1. Kliknijmy prawym klawiszem na klasie Tlo i wybierzmy opcje Open Editor. Naszym oczom ukaże się kod klasy, który będziemy musieli zmodyfikować.
2. Dopiszmy w nim tekst zaznaczony na żółto. Kod ten dopisujemy w specjalnej metodzie zwanej konstruktorem (Tlo() { .. }). Konstruktory są wykorzystywane do tworzenia nowych obiektów. A skoro chcemy, aby obiekt tło stworzył się od razu z przyciskiem to w kodzie konstruktora klasy Tlo stworzymy obiekt klasy Guzik i dodamy go do świata.

Jmk-LicznikKilikniec image06.png

3. W linijce 21 stworzyliśmy nowy obiekt klasy Guzik o nazwie obiektGuzik (dowolna nazwa bez spacji i znaków specjalnych). Obiekt został stworzony za pomocą specjalnej metody zwanej konstruktorem. Metodę to wywołuje się używając słowa new i nazwy klasy. Czyli np.: new Guzik(); Zapamiętajmy, że nowe obiekty tworzy się właśnie za pomocą konstruktorów.
4. W linijce 23 wykorzystaliśmy metodę Greenfoot’a o nazwie addObject, aby dodać stworzony obiekt do świata. Zwróćmy uwagę na wywołanie metody addObject. Metody wywołuje się poprzez napisanie jej nazwy oraz ewentualnych argumentów w nawiasach. Jeśli brak jest argumentów to podajemy puste nawiasy.
5. Na zakończenie skompilujmy projekt i uruchommy projekt klikając na przycisk Run - guzik powinien pojawić się w centrum świata.

Możliwe pytanie - jak ma się obiekt do klasy? Klasa jest gotowym przepisem na obiekt, foremką za pomocą której tworzymy obiekty. Programowanie polega na pracy z obiektami, które są tworzone z klas. Przykładem, który obrazuje tę sytuację jest samochód i jego projekt. Projekt odpowiada klasie - aby stworzyć samochód najpierw musimy stworzyć jego projekt. Obiekt odpowiada zaś konkretnemu egzemplarzowi samochodu, którym jeździmy, tankujemy go etc.
Możliwe pytanie - co to jest addObject? Metoda addObject pochodzi od twórców Greenfoot'a, wykorzystujemy ją zawsze, gdy chcemy sprawić, aby aktor pojawił się na świecie. Liczby podane jako argumenty metody są współrzędnymi określającymi gdzie pojawi się obiekt.
Napisaliśmy, że addObject jest metodą. Metody to fragmenty kody, które wywołujemy, aby wykonały dla nas jakaś operację. Najlepiej myśleć o nich jako o funkcjach matematycznych. Metody dzielimy na takie, które zwracają wyniki operacji i takie które nic nie zwracają. Np.: metoda addObject nie zwraca wyniku operacji - po prostu dodaje obiekty do świata.

Reagowanie na kliknięcia

W tym rozdziale sprawimy, aby guzik reagował na kliknięcia użytkownika i losowo zmieniał swoje położenie. Aby tego dokonać będziemy musieli poznać i zastosować instrukcję warunkową. Do dzieła:

Jmk-LicznikKilikniec image00.png
  1. Dopiszmy kod z linijek 18 - 29 do metody act.
  2. Metoda act będzie obecna w każdej klasie będącej podklasą klasy Actor (dziedziczenie!).
  3. Greenfoot cyklicznie wywołuje metodę act co pewien, niewielki fragment czasu. Zapamiętajmy więc, jeśli chcemy, aby aktor wykonywał jaką czynność musimy zaprogramować ją właśnie w metodzie act.
  4. W linijce 18 stosujemy wspomnianą instrukcję warunkową if. Sprawdza ona czy kod wpisany pomiędzy () zwraca wartość true lub false. Oczywiście jeśli kod zwraca wartość true instrukcje otoczone nawiasami {} wykonają się.
  5. A więc metoda Greenfoot.mouseClicked(this) zwraca true, gdy guzik został kliknięty.
  6. Następnie za pomocą metody getWorld pobieramy nasz świat, robimy to po to, aby pobrać rozmiary świata, które będą potrzebne do określenia nowej pozycji przycisku.
  7. W linijkach 22, 23 pobieramy właśnie szerokość i wysokość z obiektu o nazwie tlo (to jest nasz świat). Wysokość i szerokość świata są to liczby, jeśli chcemy pobrać ich wartości musimy powiedzieć Javie, że są to liczby całkowite. Dlatego w linijkach 22 i 23 napisaliśmy int, int mówi javie, że oczekujemy liczb całkowitych. Następnie po int mamy nasze dowolne nazwy zmiennych czyli szerokosc i wysokosc. Dzięki tym nazwom odniesiemy się potem do szerokości i wysokości świata. O zmiennych najlepiej myśleć jak o wartościach, do których będziemy odwoływać się potem w kodzie - zmienne te przechowują jakieś wartości.
  8. Mając już szerokość i wysokość świata za pomocą metody Greenfoot.getRandomNumber losujemy liczbę od zera do wartości podanego argumentu pomniejszonego o jeden. Tłumacząc na przykładzie: jeśli świat ma szerokość 600 pikseli metoda Greenfoot.getRandomNumber zwróci wylosowaną liczbę z przedziału 0 - 599.
  9. Ostatecznie wykorzystujemy metodę setLocation i podajemy do niej wylosowane wartości, aby zmienić lokację przycisku.
Możliwe pytanie - czym jest this? W podpunkcie 5 używamy słowa this. Jest to termin zarezerwowany przez javę jako słowo kluczowe. Oznacza to, że nie możemy wykorzystać go np.: do nazwania zmiennej lub metody (innymi słowami kluczowymi są np.: class, void, return). Objaśnienie znaczenia słowa this najlepiej zacząć od przykładu. W klasie Guzik chcemy sprawdzić czy obiekt guzika na ekranie został kliknięty. I właśnie słowo this pozwala nam będąc wewnątrz klasy Guzik wskazać, że sprawdzamy czy obiekt klasy guzik został kliknięty. Czyli za pomocą this wykorzystywanym wewnątrz klasy wskazujemy na obiekt danej klasy. Zapamiętajmy więc: za pomocą this odwołujemy się do obiektu klasy, w której użyliśmy słowa this.

To koniec, jedyne co pozostało zrobić to skompilować (Compile) i uruchomić (Run) projekt. Guzik po kliknięciu będzie zmieniał pozycję!

TL;DR

1. Kod klasy Tlo:

import greenfoot.*;
 
/**
 * Write a description of class Tlo here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class Tlo extends World
{
 
    /**
     * Constructor for objects of class Tlo.
     * 
     */
    public Tlo()
    {    
        // Create a new world with 600x400 cells with a cell size of 1x1 pixels.
        super(600, 400, 1); 
        // Tworzymy nowy obiekt typu Guzik o nazwie obiektGuzik.
        Guzik obiektGuzik = new Guzik();
        // Dodajemy obiektGuzik do świata na współrzędne 300 x 200.
        addObject(obiektGuzik, 300, 200);
    }
}

2. Kod klasy Guzik:

import greenfoot.*;
 
/**
 * Write a description of class Guzik here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class Guzik extends Actor
{
    /**
     * Act - do whatever the Guzik wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public void act() 
    {
       // Instrukcja warunkowa if (warunek) {kod do wykonania}. 
       if (Greenfoot.mouseClicked(this)) {
           // Pobieramy świat i przypisujemy go do zmiennej tlo.
           World tlo = getWorld();
           // Pobieramy szerokość i wysokość świata.
           int szerokosc = tlo.getWidth();
           int wysokosc = tlo.getHeight();
           // Losujemy nowe współrzędne guzika.
           int wylosowanyX = Greenfoot.getRandomNumber(szerokosc);
           int wylosowanyY = Greenfoot.getRandomNumber(wysokosc);
           // Ustawiamy współrzędne guzikowi.
           setLocation(wylosowanyX, wylosowanyY);
       }       
    }    
}

Poziom II: Licznik kliknięć

Omówienie zadania:

Drugi poziom będzie dotyczył licznika kliknięć. Sprawimy, że komputer policzy ile razy kliknęliśmy w guzik i wyświetli informacje na ekranie. Będziemy potrzebowali zakodować następujące funkcjonalności:

  1. Stworzenie klasy LicznikKlikniec.
  2. Przypisanie licznika kliknięć do klasy Guzik.

Realizacja zadania:

Stworzenie klasy LicznikKlikniec

LicznikKlikniec będzie aktorem. Stwórzmy więc klasę, która będzie dziedziczyła po klasie Actor. Nie ma potrzeby przypisywania obrazka, gdyż nie interesuje nas wyświetlanie statycznej grafiki, tylko rosnącej liczby. Kod klasy LicznikKlikniec prezentuje się następująco:

Jmk-LicznikKilikniec image04.png

1. Zwróćmy uwagę na instrukcję w linijce 2. Musimy ją koniecznie dopisać, gdyż pozwala nam ona korzystać z obiektów klasy Color.
2. W linijce 13 deklarujemy zmienną, która posłuży nam do zliczania kliknięć. Oczywiście na początku ustawiamy jej wartość na zero.
3. W linijkach 23 - 24 tworzymy obiekt obrazka, za pomocą którego wyświetlimy liczbę kliknięć. Zauważmy, że wykorzystujemy zapis “Klik numer: ” + licznikKlikniec, dzięki temu wyświetlimy napis na świecie.

Szczegółowe objaśnienie znaczenia parametrów konstruktora GreenfootImage, wywołanego w linijce 23,24.
  1. Na pierwszym miejscu konstruktor przyjmuje “Klik numer: ” + licznikKlikniec - “Klik numer: ” to statyczny tekst, który będzie wyświetlony na ekranie. Jednak sam tekst to za mało, chcemy jeszcze wyświetlić aktualną liczbę kliknięć, którą przechowujemy w zmiennej licznikKlikniec. A więc do tekstu “Klik numer: ” za pomocą znaku plus dodajemy wartość zmiennej licznikKlikniec. Java działa w ten sposób, że znak plus doklei liczbę ze zmiennej licznikKlikniec do tekstu. Na ekranie wyświetli się np. : Klik numer: 23.
  2. Liczba 40 jest to wielkość czcionki wykorzystanej do narysowania tekstu.
  3. Color.RED mówi nam o kolorze tekstu.
  4. Color.BLACK definiuje kolor tła obrazka.

4. W linijce 26 ustawiamy stworzony obrazek klasie.
5. Zauważmy, że wszystkie czynności wykonujemy w metodzie act. Pamiętamy o tym, że metoda ta jest cyklicznie wywoływana przez Greenfoot’a.
6. Działanie powyższego kodu będzie przebiegało następująco:

  • Metoda akt będzie wywoływana cyklicznie.
  • W metodzie tej przy każdym wywołaniu będziemy tworzyli obrazek z liczbą kliknięć do wyświetlenia.
  • Po czym przy pomocy metody setImage ustawimy ten obrazek jako obrazek klasy.

Połączenie obiektu klasy LicznikKlikniec z klasą Guzik

Zastanówmy się na tym, gdzie należy umieścić obiekt licznika. Nasz licznik będzie zliczał kliknięcia w obiekt typu Guzik. Skoro to obiekt klasy guzik potrzebuje licznika, zadeklarujmy go w klasie Guzik:

Jmk-LicznikKilikniec image08.png

Następnie musimy sprawić, aby wartość zmiennej licznikKlikniec w klasie LicznikKlikniec zwiększała się przy każdym kliknięciu:

Jmk-LicznikKilikniec image07.png

Dopiszmy kod z linijki 24 w metodzie act klasy Guzik. Kod ten zwiększy wartość zmiennej licznikKlikniec w klasie LicznikKlikniec o jeden. A skoro umieściliśmy go w instrukcji if zrobi to wtedy, gdy użytkownik kliknie w przycisk. Zauważmy tu ciekawy zapis licznik.licznikKlikniec otóż do zmiennych zadeklarowanych w innych klasach odnosimy się poprzez <nazwa_obiektu>.<nazwa_pola_w_klasie> czyli jeśli chcemy pobrać wartość zmiennej licznikKlikniec z obiektu licznik musimy napisać licznik.licznikKlikniec. Dla pewności otwórzmy klasę LicznikKlikniec i upewnijmy się, że mamy tam zmienną licznikKlikniec.
Na koniec pobierzmy obiekt licznik z obiektu guzik i dodajmy go do świata (w tym momencie sprawimy, że obiekt zostanie wyświetlony na ekranie):

Jmk-LicznikKilikniec image05.png
Możliwe pytanie - dlaczego do świata w linijce 25 dodajemy licznik, którego obiekt stworzyliśmy w klasie Guzik? Moglibyśmy przecież stworzyć nowy obiekt licznika i dodać go analogicznie jak stworzyliśmy nowy obiekt guzika w linijce 21. Do świata dodaliśmy licznik z klasy Guzik z dwóch powodów:
  1. Pamiętamy, że to w zmiennej licznika zadeklarowanego w klasie Guzik przechowujemy ile razy guzik został kliknięty (zmienna ma nazwę licznikKlikniec)
  2. A dlaczego umieściliśmy obiekt licznika w klasie Guzik? Równie dobrze moglibyśmy umieścić licznik oddzielnie ale skoro programowanie obiektowe daje nam możliwość tworzenia klas, które odzwierciedlają rzeczywistość to licznik liczący kliknięcia umieściliśmy w klasie guzik, tak jak prędkościomierz umieścilibyśmy w klasie samochod.

To koniec! Skompilujmy i uruchommy projekt.

TL;DR

Kod klasy LicznikKlikniec:

import greenfoot.*;
import java.awt.Color;
 
/**
 * Write a description of class LicznikKlikniec here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class LicznikKlikniec extends Actor
{
    // Zmienna reprezentująca ilość kliknięć.
    int licznikKlikniec = 0;
 
 
    /**
     * Act - do whatever the LicznikKlikniec wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public void act() 
    {
        // Stworzenie obiektu obrazka.
        GreenfootImage licznik = new GreenfootImage("Klik numer: " + licznikKlikniec, 40,
        Color.RED, Color.BLACK);
        // Ustawienie obrazka klasie LicznikKlikniec.
        setImage(licznik);
    }    
}

2. Klasa Guzik:

import greenfoot.*;
 
/**
 * Write a description of class Guzik here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class Guzik extends Actor
{
    // Deklarujemy i tworzymy obiekt klasy LicznikKlikniec o nazwie licznik.
    LicznikKlikniec licznik = new LicznikKlikniec();
 
    /**
     * Act - do whatever the Guzik wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public void act() 
    {
       // Instrukcja warunkowa if (warunek) {kod do wykonania}. 
       if (Greenfoot.mouseClicked(this)) {
           // Za pomocą poniższej instrukcji zwiększamy zastaną liczbę
           // kliknięć o jeden.
           licznik.licznikKlikniec = licznik.licznikKlikniec + 1;
 
           // Pobieramy świat i przypisujemy go do zmiennej tlo.
           World tlo = getWorld();
           // Pobieramy szerokość i wysokość świata.
           int szerokosc = tlo.getWidth();
           int wysokosc = tlo.getHeight();
           // Losujemy nowe współrzędne guzika.
           int wylosowanyX = Greenfoot.getRandomNumber(szerokosc);
           int wylosowanyY = Greenfoot.getRandomNumber(wysokosc);
           // Ustawiamy współrzędne guzikowi.
           setLocation(wylosowanyX, wylosowanyY);
       }       
    }    
}

3. Klasa Tlo:

import greenfoot.*;
 
/**
 * Write a description of class Tlo here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class Tlo extends World
{
 
    /**
     * Constructor for objects of class Tlo.
     * 
     */
    public Tlo()
    {    
        // Create a new world with 600x400 cells with a cell size of 1x1 pixels.
        super(600, 400, 1); 
        // Tworzymy nowy obiekt typu Guzik o nazwie obiektGuzik.
        Guzik obiektGuzik = new Guzik();
        // Dodajemy obiektGuzik do świata na współrzędne 300 x 200.
        addObject(obiektGuzik, 300, 200);
        // Dodanie licznika z obiektu obiektGuzik do świata.
        addObject(obiektGuzik.licznik, 200, 20);
    }
}

Pomysłem do dalszego rozwoju scenariusza może być dodanie kodu, który będzie odmierzał czas i zakańczał działanie aplikacji np.: po 30 sekundach. W takim wypadku łatwo będzie sprawdzić kto osiągnie najwięcej kliknięć w określonym czasie.