Projekt Snake



Projekt Snake opisany w tym wpisie dotyczy prostej i znanej wszystkim gry w której to użytkownik poruszając się wężykiem stara się uzbierać jak największą ilość punktów.

Sam projekt skierowany jest do osób średnio zaawansowanych jak i dopiero zaczynających. Wpis ma na celu przedstawienia mojego pomysłu i podejścia do gamedevu – tworzenia gier ale również do zachęcenia was, czytelników do takich projektów. Jeśli więc coś wyda wam się niezrozumiałe lub nie dokładnie opisane zapraszam do komentarzy lub innej formy kontaktu z naszą grupą – postaramy się pomóc tak szybko jak tylko to możliwe.

Sama gra napisana jest w PROCESSINGU natomiast sterowanie odbywa się przy pomocy pilota i ARDUINO. Cały opisany kod dostępny jest na naszym githubie, osoby chętne zachęcam do pobrania i przetestowania. W przypadku błędów/uwag/ pomysłów na modyfikację po raz kolejny zapraszam do komentarzy lub kontaktu z naszą grupą.

Odnośnie technologi i podziału poradniku – poradnik składał się będzie z dwóch części:

  • HARDWARE gdzie postaram się omówić wszystko po stornie arduino w raz z całym sprzętem    (Do pisania kodu pod arduino  korzystam z Visual Studio 2017 oraz dodatku Visual Micro)
  • SOFTWARE gdzie przedstawiony zostanie i omówiony cały kod po stronie komputera                    (Do pisania kodu gry korzystam z Eclipse (PROCESSING oparty jest na javie) z czego wynikać mogą  drobne różnice w porównaniu do PROCESSING IDE)
    • Odbieranie danych i poruszanie (proste)
    • Wychodzenie po za bok ekranu
    • Zbieranie punktów
    • Kolizje
    • Detale (grafik, punkty)
    • Podsumowanie i zapowiedź

Część pierwsza ARDUINO

Potrzebny sprzęt:
– Arduino UNO lub inna płytka
– moduł Odbiornik podczerwieni
– płytka stykowa, kilka kabli
– kable USB do komunikacji komputer <=> arduino

Wprowadzenie do obsługi modułu i pilota: https://learnduino.pl/arduino-remote-control/ 

Schemat połączenia z modułem
GND <-> GND
+5V <-> +5V
PIN 11 <-> INPUT

Wszystkie niezbędne informacje zostały opisane  w poście powyżej. Osoby nie zapoznane z tematem zachęcam do przeczytania.

[pastacode lang=”cpp” manual=”%23include%20%3CIRremote.h%3E%20%2F%2F%20biblioteka%20%0A%0AIRrecv%20irrecv(11)%3B%20%2F%2F%20pin%2011%20%0Adecode_results%20results%3B%20%0A%0Avoid%20setup()%0A%7B%0A%09Serial.begin(9600)%3B%0A%09irrecv.enableIRIn()%3B%0A%7D%0A%0Avoid%20loop()%0A%7B%0A%09if%20(irrecv.decode(%26results))%0A%09%7B%0A%09%09switch%20(results.value)%20%2F%2F%20sprawdzamy%20jaki%20przycisk%20%0A%09%09%7B%0A%09%09case%200xFF609F%3A%20%2F%2F%20up%20%0A%09%09%7B%0A%09%09%09Serial.println(%22UP%22)%3B%0A%09%09%09break%3B%0A%09%09%7D%0A%09%09case%200xFF22DD%3A%20%2F%2F%20down%20%0A%09%09%7B%0A%09%09%09Serial.println(%22DOWN%22)%3B%0A%09%09%09break%3B%0A%09%09%7D%0A%09%09case%200xFFE21D%3A%20%2F%2F%20left%20%0A%09%09%7B%0A%09%09%09Serial.println(%22LEFT%22)%3B%0A%09%09%09break%3B%0A%09%09%7D%0A%09%09case%200xFF02FD%3A%20%2F%2F%20right%0A%09%09%7B%0A%09%09%09Serial.println(%22RIGHT%22)%3B%0A%09%09%09break%3B%0A%09%09%7D%0A%09%09case%200xFFE01F%3A%20%2F%2F%20enter%0A%09%09%7B%0A%09%09%09Serial.println(%22ENTER%22)%3B%0A%09%09%09break%3B%0A%09%09%7D%0A%09%09%7D%0A%0A%09%09irrecv.resume()%3B%0A%09%7D%0A%0A%09delay(100)%3B%0A%7D” message=”” highlight=”” provider=”manual”/]

W skrócie jeśli wciśniemy przycisk (strzałkę do góry na pilocie) wysyłany jest komunikat “UP”, jeśli coś innego np Enter wysyłany jest komunikat “ENTER” itd…

Po stronie arduino to wszystko z mojej strony. Uwaga w tym miejscu ważne jest aby wprowadzić swoje kody przycisków, zanim przejdziemy do dalszej części.

(Jeżeli coś wydało wam się nie zrozumiałe lub nie dokładnie opisane zachęcam do komentarzy i pytań, w przyszłości mam pomysł na kilka podobnych projektów gier, jeśli więc jesteście zainteresowani tym tematem ważne jest aby już na początku zrozumieć jak jak najwięcej).

Część druga Processing

Zanim jednak przejdę do pierwszego pod tematu warto by omówić schemat całej aplikacji i organizację tego projektu. Całość składać się będzie z kilku funkcji z czego każda będzie miała odpowiednie zadanie do wykonania – wszystkie funkcje zostaną opisane i omówione.

[pastacode lang=”java” manual=”package%20snakeld%3B%20%2F%2F%20%0A%0Aimport%20processing.core.PApplet%3B%20%2F%2F%20%0A%0A%0Apublic%20class%20SnakeLD%20extends%20PApplet%20%7B%20%2F%2F%20%0A%0A%09public%20void%20setup()%20%7B%0A%09%7D%0A%0A%09public%20void%20draw()%20%7B%0A%0A%09%7D%0A%09%0A%09public%20void%20settings()%20%20%7B%20%2F%2F%20%0A%09%09%0A%09%7D%0A%0A%09public%20static%20void%20main(String%20_args%5B%5D)%20%7B%0A%09%09PApplet.main(new%20String%5B%5D%20%7B%20SnakeLD.class.getName()%20%7D)%3B%20%2F%2F%20%0A%09%7D%20%0A%0A%7D%0A” message=”” highlight=”” provider=”manual”/]

Fragmentu zaznaczone komentarzami “//” nas nie interesuję, są to elementy wymagane w eclipse które nie są konieczne jeśli korzystamy z processing IDE. Tak naprawdę interesuje nas na  razie zawartość funkcji draw() oraz setup()*

Uwaga w przypadku eclipse wielkość okna definiujemy w funkcji settings () natomiast w przypadku Processing IDE w funkcji setup(). Wielkość okna jest stała zatem wspominam o tym tylko teraz.

(Jeżeli coś wydało wam się nie zrozumiałe lub nie dokładnie opisane zachęcam do komentarzy i pytań, w przyszłości mam pomysł na kilka podobnych projektów gier, jeśli więc jesteście zainteresowani tym tematem ważne jest aby już na początku zrozumieć jak jak najwięcej).

Pod temat pierwszy:
Odbieranie danych i poruszanie (proste)

Przede wszystkim odbieranie danych z Arduino a dokładnie komunikacja z portem COM.
Po raz kolejny nie ma sensu przepisywać coś co już kiedyś opisałem tutaj: https://learnduino.pl/tworzenie-wykresow-z-uzyciem-processingu/

Na początku tworzymy dwie nowe zmienne String .

[pastacode lang=”java” manual=”String%20com%20%3D%20null%2C%20v%20%3D%20%22DOWN%22%3B” message=”” highlight=”” provider=”manual”/]

W pierwszej zapisane będę dane odebrane z portu COM druga określa aktualny kierunek naszego węża.

Odbieranie danych odbywa się w funkcji keybord() , funkcja ta ma za zadanie zebrać dane a następnie je porównać. Brzmi skomplikowanie ale w rzeczywistości wszystko jest bardo proste.

[pastacode lang=”java” manual=”com%20%3D%20myPort.readStringUntil(lf).trim()%3B” message=”” highlight=”” provider=”manual”/]

Ważne aby na końcu dodać .trim(); co pozwoli uniknąć nam białych znaków.

[pastacode lang=”markup” manual=”com.equals(%22UP%22)%20%0A%2F%2Fobjekt_string.equals(objekt_do_por%C3%B3wnania)%3B” message=”” highlight=”” provider=”manual”/]

Funkcja ta służy do porównywania obiektów tekstowych jakimi są zmienne String.
Ważna jest aby nie korzystać z operatorów porównania (operator “==”)który w różnych sytuacjach może zadziałać błędnie.

Drugą funkcją jest funkcja moveLoop() to w niej na podstawie odebranych danych zmieniana będzie pozycja naszego gracza.

[pastacode lang=”java” manual=”void%20moveLoop()%20%7B%0A%09%09if%20(v%20%3D%3D%20%22UP%22)%20%7B%0A%09%09%09position%20%3D%20new%20PVector(position.x%2C%20position.y%20-%201)%3B%0A%09%09%7D%0A%09%09if%20(v%20%3D%3D%20%22DOWN%22)%20%7B%0A%09%09%09position%20%3D%20new%20PVector(position.x%2C%20position.y%20%2B%201)%3B%0A%0A%09%09%7D%0A%09%09if%20(v%20%3D%3D%20%22LEFT%22)%20%7B%0A%09%09%09position%20%3D%20new%20PVector(position.x%20-%201%2C%20position.y)%3B%0A%0A%09%09%7D%0A%09%09if%20(v%20%3D%3D%20%22RIGHT%22)%20%7B%0A%09%09%09position%20%3D%20new%20PVector(position.x%20%2B%201%2C%20position.y)%3B%0A%0A%09%09%7D%0A%09%7D” message=”” highlight=”” provider=”manual”/]

Sprawdzamy w którą stronę ma się poruszać nasz wąż i zmieniamy jego pozycję.

Dlaczego nie robimy tego od razu w funkcji keybord()? 
Odpowiedź jest bardzo prosta, nasz wąż może się poruszać jeśli nic nie zostało wciśnięte.  

Zmieniamy pozycję naszego wektora (wektor położenia obiektu) czyli zmieniamy pozycję kwadratu. W tym miejscu kończy się na razie poruszanie naszym obiektem, do tematu jeszcze wrócimy przy rozbudowywaniu poruszania o system kolizji.

Trzecią dodaną funkcją jest funkcja draw_stuff(), to właśnie tu opisane będzie wszystko co ma zostać narysowane. Na ten moment ważny jest tylko jeden fragment kodu.

[pastacode lang=”java” manual=”%09%09rect(position.x%20*%2032%2C%20position.y%20*%2032%2C%2032%2C%2032)%3B” message=”” highlight=”” provider=”manual”/]

Mamy kwadrat o wymiarach 32 x 32 którego przesuwamy o:
– 32 * wektor przesunięcia X
– 32 * wektor przesunięcia Y

Początkowa pozycja naszego wektora to (5,5) a wiec pozycja 160, 160 względem sceny renderowania…
– ruch w prawo -> uzyskujemy wektor (6,5) czyli pozycję 192, 160 względem naszego sceny renderowania
– ruch w lewo – > uzyskujemy wektor (4,5) czyli pozycję 128, 160 względem naszego sceny renderowania
– ruch do góry – > uzyskujemy wektor (5,4) czyli pozycję 160, 128 względem naszego sceny renderowania
– ruch na dół- > uzyskujemy wektor (5,6) czyli pozycję 160, 192 względem naszego sceny renderowania
itd…

Aby dokładnie zrozumieć zagadnienie poruszania się polecam ołówek i kartkę w kratkę.

Końcowym etapem jest modyfikacja funkcji draw() oraz setup() tutaj wszystko powinno być raczej proste  i zrozumiał.  Efektem uruchomienia tego kodu będzie kwadrat który bardzo szybko będzie się poruszał w dół.

[pastacode lang=”java” manual=”package%20snakeld%3B%0A%0Aimport%20processing.core.PApplet%3B%0Aimport%20processing.core.PVector%3B%0Aimport%20processing.serial.Serial%3B%0A%0Apublic%20class%20SnakeLD%20extends%20PApplet%20%7B%0A%0A%09int%20lf%20%3D%2010%3B%0A%09Serial%20myPort%3B%0A%0A%09String%20com%20%3D%20null%2C%20v%20%3D%20%22DOWN%22%3B%0A%09PVector%20position%20%3D%20new%20PVector(5%2C%205)%3B%0A%0A%09public%20static%20void%20main(String%20_args%5B%5D)%20%7B%0A%09%09PApplet.main(new%20String%5B%5D%20%7B%20SnakeLD.class.getName()%20%7D)%3B%0A%09%7D%0A%0A%09public%20void%20keybord()%20%7B%0A%0A%09%09while%20(myPort.available()%20%3E%200)%20%7B%0A%0A%09%09%09com%20%3D%20myPort.readStringUntil(lf).trim()%3B%0A%0A%09%09%09if%20(com%20!%3D%20null)%20%7B%0A%0A%09%09%09%09if%20(com.equals(%22UP%22))%20%7B%0A%09%09%09%09%09v%20%3D%20%22UP%22%3B%0A%09%09%09%09%7D%0A%09%09%09%09if%20(com.equals(%22DOWN%22))%20%7B%0A%09%09%09%09%09v%20%3D%20%22DOWN%22%3B%0A%09%09%09%09%7D%0A%09%09%09%09if%20(com.equals(%22LEFT%22))%20%7B%0A%09%09%09%09%09v%20%3D%20%22LEFT%22%3B%0A%09%09%09%09%7D%0A%09%09%09%09if%20(com.equals(%22RIGHT%22))%20%7B%0A%09%09%09%09%09v%20%3D%20%22RIGHT%22%3B%0A%09%09%09%09%7D%0A%09%09%09%09if%20(com.equals(%22ENTER%22))%20%7B%0A%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%09%09%7D%0A%09%7D%0A%0A%09void%20moveLoop()%20%7B%0A%09%09if%20(v%20%3D%3D%20%22UP%22)%20%7B%0A%09%09%09position%20%3D%20new%20PVector(position.x%2C%20position.y%20-%201)%3B%0A%09%09%7D%0A%09%09if%20(v%20%3D%3D%20%22DOWN%22)%20%7B%0A%09%09%09position%20%3D%20new%20PVector(position.x%2C%20position.y%20%2B%201)%3B%0A%0A%09%09%7D%0A%09%09if%20(v%20%3D%3D%20%22LEFT%22)%20%7B%0A%09%09%09position%20%3D%20new%20PVector(position.x%20-%201%2C%20position.y)%3B%0A%0A%09%09%7D%0A%09%09if%20(v%20%3D%3D%20%22RIGHT%22)%20%7B%0A%09%09%09position%20%3D%20new%20PVector(position.x%20%2B%201%2C%20position.y)%3B%0A%0A%09%09%7D%0A%09%7D%0A%0A%09public%20void%20draw_stuff()%20%7B%0A%09%09noStroke()%3B%0A%09%09background(255)%3B%0A%09%09fill(255%2C%200%2C%200)%3B%0A%09%09rect(position.x%20*%2032%2C%20position.y%20*%2032%2C%2032%2C%2032)%3B%0A%09%7D%0A%0A%09public%20void%20settings()%20%7B%0A%09%09size(576%2C%20576)%3B%20%0A%09%7D%0A%0A%09public%20void%20setup()%20%7B%0A%09%09color(123%2C%200%2C%200)%3B%0A%09%09myPort%20%3D%20new%20Serial(this%2C%20Serial.list()%5B0%5D%2C%209600)%3B%0A%09%09myPort.clear()%3B%0A%0A%09%7D%0A%0A%09public%20void%20draw()%20%7B%0A%0A%09%09keybord()%3B%0A%0A%09%09moveLoop()%3B%0A%09%09draw_stuff()%3B%0A%0A%09%7D%0A%7D” message=”” highlight=”” provider=”manual”/]

(Jeżeli coś wydało wam się nie zrozumiałe lub nie dokładnie opisane zachęcam do komentarzy i pytań, w przyszłości mam pomysł na kilka podobnych projektów gier, jeśli więc jesteście zainteresowani tym tematem ważne jest aby już na początku zrozumieć jak jak najwięcej).

Pod temat drugi:
Wychodzenie po za bok ekranu

[pastacode lang=”java” manual=”void%20border()%20%7B%0A%09%09if%20(position.x%20%3E%2017)%20%7B%0A%09%09%09position.x%20%3D%200%3B%0A%09%09%7D%0A%09%09if%20(position.x%20%3C%200)%20%7B%0A%09%09%09position.x%20%3D%2017%3B%0A%09%09%7D%0A%0A%09%09if%20(position.y%20%3E%2017)%20%7B%0A%09%09%09position.y%20%3D%200%3B%0A%09%09%7D%0A%09%09if%20(position.y%20%3C%200)%20%7B%0A%09%09%09position.y%20%3D%2017%3B%0A%09%09%7D%0A%09%7D” message=”” highlight=”” provider=”manual”/]

Opisany fragment będzie bardzo krótki i szybki, dotyczy on interakcji z bokami ekrany.  W nowej funkcji sprawdzamy kolejno czy (wektor pozycji) pozycja X oraz Y  nie wychodzi po za ekran a jeśli tak to przenosimy gracz na drugą stroną (zmieniamy wektor).

Efektem tej modyfikacji będzie zapętlenie ruchu naszej postaci, problemem nadal jednak jest szybkość poruszania się. Dodamy więc kolejną funkcję która pozwoli nam ograniczyć poruszanie się gracza.

Schemat działania oparty jest na millis() o podobnym sposobie pisałem już kiedyś tutaj: https://learnduino.pl/arduino-millis-vs-delay/

Po pierwsze dodamy dwie nowe zmienne typu int – pierwsza oznacz czas między kolejnym ruchem, druga rozpoczyna odliczanie.

[pastacode lang=”java” manual=”int%20%20time_break%20%3D%20200%2C%20start%20%3D%20millis()%2C%20lf%20%3D%2010%3B” message=”” highlight=”” provider=”manual”/]

Kolejnym etapem jest dodanie funkcji pause() w funkcji tej sprawdzamy czy czas od aktualizacji odliczania jest większy niż czas między ruchami:
– jeśli tak zwracamy true  i aktualizujemy czas
– jeśli nie zwracamy false i  aktualizujemy czas

[pastacode lang=”java” manual=”boolean%20pauses()%20%7B%0A%09%09if%20(millis()%20-%20start%20%3E%3D%20time_break)%20%7B%0A%09%09%09start%20%3D%20millis()%3B%0A%09%09%09return%20true%3B%0A%09%09%7D%20else%20%7B%0A%09%09%09return%20false%3B%0A%09%09%7D%0A%09%7D” message=”” highlight=”” provider=”manual”/]

Po uruchomieniu programy obiekt będzie się poruszał z określoną przez nas szybkością oraz w określonym przez nas kierunku.

 

[pastacode lang=”java” manual=”package%20snakeld%3B%0A%0Aimport%20processing.core.PApplet%3B%0Aimport%20processing.core.PVector%3B%0Aimport%20processing.serial.Serial%3B%0A%0Apublic%20class%20SnakeLD%20extends%20PApplet%20%7B%0A%0A%09int%20time_break%20%3D%20200%2C%20start%20%3D%20millis()%2C%20lf%20%3D%2010%3B%0A%09Serial%20myPort%3B%0A%0A%09String%20com%20%3D%20null%2C%20v%20%3D%20%22DOWN%22%3B%0A%09PVector%20position%20%3D%20new%20PVector(5%2C%205)%3B%0A%0A%09public%20static%20void%20main(String%20_args%5B%5D)%20%7B%0A%09%09PApplet.main(new%20String%5B%5D%20%7B%20SnakeLD.class.getName()%20%7D)%3B%0A%09%7D%0A%0A%09void%20border()%20%7B%0A%09%09if%20(position.x%20%3E%2017)%20%7B%0A%09%09%09position.x%20%3D%200%3B%0A%09%09%7D%0A%09%09if%20(position.x%20%3C%200)%20%7B%0A%09%09%09position.x%20%3D%2017%3B%0A%09%09%7D%0A%0A%09%09if%20(position.y%20%3E%2017)%20%7B%0A%09%09%09position.y%20%3D%200%3B%0A%09%09%7D%0A%09%09if%20(position.y%20%3C%200)%20%7B%0A%09%09%09position.y%20%3D%2017%3B%0A%09%09%7D%0A%09%7D%0A%0A%09boolean%20pauses()%20%7B%0A%09%09if%20(millis()%20-%20start%20%3E%3D%20time_break)%20%7B%0A%09%09%09start%20%3D%20millis()%3B%0A%09%09%09return%20true%3B%0A%09%09%7D%20else%20%7B%0A%09%09%09return%20false%3B%0A%09%09%7D%0A%09%7D%0A%0A%09public%20void%20keybord()%20%7B%0A%0A%09%09while%20(myPort.available()%20%3E%200)%20%7B%0A%0A%09%09%09com%20%3D%20myPort.readStringUntil(lf).trim()%3B%0A%0A%09%09%09if%20(com%20!%3D%20null)%20%7B%0A%0A%09%09%09%09if%20(com.equals(%22UP%22))%20%7B%0A%09%09%09%09%09v%20%3D%20%22UP%22%3B%0A%09%09%09%09%7D%0A%09%09%09%09if%20(com.equals(%22DOWN%22))%20%7B%0A%09%09%09%09%09v%20%3D%20%22DOWN%22%3B%0A%09%09%09%09%7D%0A%09%09%09%09if%20(com.equals(%22LEFT%22))%20%7B%0A%09%09%09%09%09v%20%3D%20%22LEFT%22%3B%0A%09%09%09%09%7D%0A%09%09%09%09if%20(com.equals(%22RIGHT%22))%20%7B%0A%09%09%09%09%09v%20%3D%20%22RIGHT%22%3B%0A%09%09%09%09%7D%0A%09%09%09%09if%20(com.equals(%22ENTER%22))%20%7B%0A%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%09%09%7D%0A%09%7D%0A%0A%09void%20moveLoop()%20%7B%0A%09%09if%20(v%20%3D%3D%20%22UP%22)%20%7B%0A%09%09%09position%20%3D%20new%20PVector(position.x%2C%20position.y%20-%201)%3B%0A%09%09%7D%0A%09%09if%20(v%20%3D%3D%20%22DOWN%22)%20%7B%0A%09%09%09position%20%3D%20new%20PVector(position.x%2C%20position.y%20%2B%201)%3B%0A%0A%09%09%7D%0A%09%09if%20(v%20%3D%3D%20%22LEFT%22)%20%7B%0A%09%09%09position%20%3D%20new%20PVector(position.x%20-%201%2C%20position.y)%3B%0A%0A%09%09%7D%0A%09%09if%20(v%20%3D%3D%20%22RIGHT%22)%20%7B%0A%09%09%09position%20%3D%20new%20PVector(position.x%20%2B%201%2C%20position.y)%3B%0A%0A%09%09%7D%0A%09%7D%0A%0A%09public%20void%20draw_stuff()%20%7B%0A%09%09noStroke()%3B%0A%09%09background(255)%3B%0A%09%09fill(255%2C%200%2C%200)%3B%0A%09%09rect(position.x%20*%2032%2C%20position.y%20*%2032%2C%2032%2C%2032)%3B%0A%09%7D%0A%0A%09public%20void%20settings()%20%7B%0A%09%09size(576%2C%20576)%3B%20%2F%2F%20576%20x%20576%0A%09%7D%0A%0A%09public%20void%20setup()%20%7B%0A%09%09color(123%2C%200%2C%200)%3B%0A%09%09myPort%20%3D%20new%20Serial(this%2C%20Serial.list()%5B0%5D%2C%209600)%3B%0A%09%09myPort.clear()%3B%0A%0A%09%7D%0A%0A%09public%20void%20draw()%20%7B%0A%0A%09%09keybord()%3B%0A%0A%09%09if%20(pauses())%20%7B%0A%09%09%09moveLoop()%3B%0A%09%09%7D%0A%0A%09%09border()%3B%0A%0A%09%09draw_stuff()%3B%0A%0A%09%7D%0A%7D” message=”” highlight=”” provider=”manual”/]

(Jeżeli coś wydało wam się nie zrozumiałe lub nie dokładnie opisane zachęcam do komentarzy i pytań, w przyszłości mam pomysł na kilka podobnych projektów gier, jeśli więc jesteście zainteresowani tym tematem ważne jest aby już na początku zrozumieć jak jak najwięcej).

Pod temat trzeci:
Zbieranie punktów

W tym fragmencie postaram się opisać system dzięki któremu możliwe będzie zdobywanie punktów i rozwijanie naszego węża.Nie ukrywam że jest to najbardziej zaawansowana a co za tym idzie jest to najtrudniejszy moment w tym projekcie. Po pierwsze zajmiemy się zbieraniem punktów, konieczne będzie wprowadzenie kilku zmiennych i obiektów.

Pierwszym etapem który musimy omówić jest wektor. Wektory są elementem języków programowania ale nie chodzi tu o te znane z matematyki czy fizyki. Najprościej mówiąc wektor to tablica (zbiór danych) które dowolnie możemy zmieniać w czasie działania programu.

Dla osób chcących dowiedzieć się więcej: https://pl.wikipedia.org/wiki/Tablica_(informatyka)

Zanim przejdziemy dalej przedstawię jeszcze zbiór funkcji z jakich możemy korzystać kiedy posługujemy się wektorem.

[pastacode lang=”java” manual=”ArrayList%3CPVector%3E%20vectors%20%3D%20new%20ArrayList%3CPVector%3E()%3B%20%2F%2F%20tworzymy%20nowy%20wektor%20%0A%0Avectors.add(new%20PVector(0%2C%202))%3B%20%2F%2F%20dodajemy%20nowa%20pozycj%C4%99%20(wektor%20pozycji)%20%0A%0Avectors.add(0%2C%20new%20PVector(vectors.get(0).x%2C%20vectors.get(0).y%20%2B%201))%3B%20%2F%2F%20dodajemy%20nowa%20pozycj%C4%99%20(wektor%20pozycji)%20w%20okre%C5%9Blonym%20miejscu%20(zero%20czyli%20na%20pocz%C4%85tku%20wektora)%0A%0Avectors.size()%3B%20zwraca%20ilo%C5%9B%C4%87%20element%C3%B3w%20w%20wektorze%20%0A%0Avectors.remove(0)%3B%20%2F%2F%20usuwamy%20okre%C5%9Blony%20element%20z%20wektora%20(zero%20czyli%20pocz%C4%85tek%20wektora)%0A%0Avectors.remove(vectors.size()%20-%201)%3B%20%2F%2F%20usuwamy%20ostatni%20element%20%0A%0Avectors.clear()%3B%20%2F%2F%20czy%C5%9Bcimy%20wektor%20%0A” message=”” highlight=”” provider=”manual”/]

 

Uwaga w Eclipse korzystam z wektora (listy) dostępnej w języku JAVA, jeśli nie korzystasz z tego IDE tylko z PROCESSING IDE powinieneś skorzystać z ArrayList.

 

PVectror position zastąpiliśmy nowym wektorem.

[pastacode lang=”java” manual=”%09ArrayList%3CPVector%3E%20vectors%20%3D%20new%20ArrayList%3CPVector%3E()%3B” message=”” highlight=”” provider=”manual”/]

Po tej zmianie konieczne jest zmian w prawie wszystkich funkcji które do tej pory zostały stworzone. Postaram się teraz pokrótce opisać sens tych zmian.

[pastacode lang=”java” manual=”void%20border()%20%7B%0A%09%09if%20(vectors.get(0).x%20%3E%2017)%20%7B%0A%09%09%09vectors.get(0).x%20%3D%200%3B%0A%09%09%7D%0A%09%09if%20(vectors.get(0).x%20%3C%200)%20%7B%0A%09%09%09vectors.get(0).x%20%3D%2017%3B%0A%09%09%7D%0A%0A%09%09if%20(vectors.get(0).y%20%3E%2017)%20%7B%0A%09%09%09vectors.get(0).y%20%3D%200%3B%0A%09%09%7D%0A%09%09if%20(vectors.get(0).y%20%3C%200)%20%7B%0A%09%09%09vectors.get(0).y%20%3D%2017%3B%0A%09%09%7D%0A%09%7D” message=”” highlight=”” provider=”manual”/]

Zmieniony został zapis, ale działanie funkcji takie samo.

[pastacode lang=”java” manual=”vectors.get(0).x%0Avectors.get(0).y” message=”” highlight=”” provider=”manual”/]

To pozycje X i Y pierwszego elementu czyli głowy węża.

[pastacode lang=”java” manual=”void%20moveLoop()%20%7B%0A%09%09if%20(v%20%3D%3D%20%22UP%22)%20%7B%0A%09%09%09vectors.add(0%2C%20new%20PVector(vectors.get(0).x%2C%20vectors.get(0).y%20-%201))%3B%0A%09%09%09vectors.remove(vectors.size()%20-%201)%3B%0A%09%09%7D%0A%09%09if%20(v%20%3D%3D%20%22DOWN%22)%20%7B%0A%09%09%09vectors.add(0%2C%20new%20PVector(vectors.get(0).x%2C%20vectors.get(0).y%20%2B%201))%3B%0A%09%09%09vectors.remove(vectors.size()%20-%201)%3B%0A%09%09%7D%0A%09%09if%20(v%20%3D%3D%20%22LEFT%22)%20%7B%0A%09%09%09vectors.add(0%2C%20new%20PVector(vectors.get(0).x%20-%201%2C%20vectors.get(0).y))%3B%0A%09%09%09vectors.remove(vectors.size()%20-%201)%3B%0A%09%09%7D%0A%09%09if%20(v%20%3D%3D%20%22RIGHT%22)%20%7B%0A%09%09%09vectors.add(0%2C%20new%20PVector(vectors.get(0).x%20%2B%201%2C%20vectors.get(0).y))%3B%0A%09%09%09vectors.remove(vectors.size()%20-%201)%3B%0A%09%09%7D%0A%09%7D” message=”” highlight=”” provider=”manual”/]

W tej funkcji zaszło bardzo dużo zmian ale to właśnie dzięki nim możliwe jest od teraz prawidłowe poruszanie naszym wężem.

[pastacode lang=”java” manual=”%09vectors.add(0%2C%20new%20PVector(vectors.get(0).x%2C%20vectors.get(0).y%20%2B%201))%3B%0A%09%09%09″ message=”” highlight=”” provider=”manual”/]

Dodajemy nową pozycję na początku wektora, tym samym zmieniając pozycję głowy naszego węża a co za tym idzie zmieniając cała jego pozycję. Sens tej operacji jest bardzo prosty, przesuwamy głową na nową pozycję, pierwszą część ciała na stare miejsce głowy, drugą część ciała na stara miejsce pierwszej części ciała, trzecią część ciała na stara miejsce drugiej części ciała, czwarta na trzecią, piątą na czwartą itd… zależnie ile części ciała ma nasz wąż.

[pastacode lang=”java” manual=”%09%09%09vectors.remove(vectors.size()%20-%201)%3B” message=”” highlight=”” provider=”manual”/]

Na koniec usuwamy ostanie miejsce gdyż nie jest już ono nam potrzebne. Ostatni fragment przesunął się na przed ostatni pozycję. Przedstawiona tutaj operacja zachodzi w kółko dzięki czemu możliwy jest płynny ruch.

Ostatnią zaktualizowaną funkcją jest funkcja draw_stuff, tym razem pojawia się tutaj pętla for w której ustawiany jest kolor (zależnie czy głowa czy część ciała) a następnie dany element jest rysowany.

Uwaga, pętla napisana jest w  taki sposób aby wszystko rysowana było od tyłu, tzn jako pierwszy koniec ogona a głowa jako ostatnia. Nie ma to szczególnego znaczenia ale daje to fajny efekt przy kolizjach, a sama pętla wygląda na super trudną do zrozumienia (ale tylko z pozoru).

[pastacode lang=”java” manual=”void%20draw_stuff()%20%7B%0A%09%09noStroke()%3B%0A%09%09background(255)%3B%0A%0A%09%09for%20(int%20i%20%3D%20vectors.size()%20-%201%3B%20i%20%3E%3D%200%3B%20i–)%20%7B%0A%09%09%09if%20(i%20%3D%3D%200)%20%7B%0A%09%09%09%09fill(0%2C%200%2C%20255)%3B%0A%09%09%09%7D%20else%20%7B%0A%09%09%09%09fill(0%2C%20255%2C%200)%3B%0A%09%09%09%7D%0A%0A%09%09%09rect(vectors.get(i).x%20*%2032%2C%20vectors.get(i).y%20*%2032%2C%2032%2C%2032)%3B%0A%09%09%7D%0A%0A%09%7D” message=”” highlight=”” provider=”manual”/]

Ostatnim elementem jest dodania nowych części ciała do naszego węża ( tak aby początek gry odbywał się kiedy wąż ma już jakaś swoją początkową wielkość, a kolejne elementy będzie zdobywał poprzez zbieranie punktów). W tym celu należy uzupełnić nasz wektor kilkoma (trzema) fragmentami, odbywa się to w funkcji setup().

[pastacode lang=”java” manual=”%09%09vectors.add(new%20PVector(0%2C%202))%3B%0A%09%09vectors.add(new%20PVector(0%2C%201))%3B%0A%09%09vectors.add(new%20PVector(0%2C%200))%3B” message=”” highlight=”” provider=”manual”/]

W tym momencie jesteśmy już w stanie poruszać się czymś co przypomina węża, pora więc na najważniejszy element gry czyli zbieranie punktów. Po raz kolejny zaczynamy więc od dodania nowego systemu, w którym zawarte będzie zbieranie punktów oraz zwiększanie wielkości węża.

[pastacode lang=”java” manual=”int%20time_break%20%3D%20200%2C%20start%20%3D%20millis()%2C%20lf%20%3D%2010%2C%20point%20%3D%200%3B” message=”” highlight=”” provider=”manual”/]

Na początku zaczynamy od dodania nowej zmiennej w które zapisany będzie ilość uzyskanych punktów.

[pastacode lang=”java” manual=”PVector%20bonus%20%3D%20new%20PVector(5%2C%205)%3B” message=”” highlight=”” provider=”manual”/]

Kolejnym etapem jest dodanie obiektu który będzie reprezentował nasze punkty “jedzonko”.

[pastacode lang=”java” manual=”void%20getPoint()%20%7B%0A%09%09if%20(bonus.x%20%3D%3D%20vectors.get(0).x%20%26%26%20bonus.y%20%3D%3D%20vectors.get(0).y)%20%7B%20%2F%2F%20sprawdzamy%20czy%20pozycja%20g%C5%82owy%20jest%20taka%20sama%20jak%20obiektu%20%22jedzenie%22%0A%09%09%09point%20%3D%20point%20%2B%201%3B%20%2F%2F%20zwi%C4%99kszamy%20ilos%C4%87%20punkt%C3%B3w%20%0A%09%09%09bonus%20%3D%20new%20PVector((int)%20random(0%2C%2016)%2C(int)%20random(0%2C%2016))%3B%20%2F%2F%20losujemy%20now%C4%85%20pozycj%C4%99%20%22obiektu%20jedzenie%22%0A%0A%09%09%09for%20(int%20i%20%3D%200%3B%20i%20%3C%20vectors.size()%3B%20i%2B%2B)%20%7B%20%0A%09%09%09%09if%20(bonus.x%20%3D%3D%20vectors.get(i).x%20%26%26%20bonus.y%20%3D%3D%20vectors.get(i).y)%20%7B%0A%0A%09%09%09%09%09bonus%20%3D%20new%20PVector((int)%20random(0%2C%2016)%2C(int)%20random(0%2C%2016))%3B%0A%0A%09%09%09%09%09i%20%3D%200%3B%0A%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%0A%09%09%09vectors.add(new%20PVector(vectors.get(vectors.size()%20-%201).x%2C%20vectors%0A%09%09%09%09%09.get(vectors.size()%20-%201).y))%3B%20%2F%2F%20zwi%C4%99kszamy%20wilkos%C4%87%20w%C4%99za%20%0A%09%09%7D%0A%09%7D” message=”” highlight=”” provider=”manual”/]

Najważniejszym elementem jest funkcja getPoitn(), w jej wnętrzu sprawdzamy czy gracz ma tą same pozycje co obiekt “jedzenie” a jeśli tak jest zwiększamy jego wielkość i ilość zdobytych punktów, oraz losujemy nowe położenie obiektu “jedzenie” .

[pastacode lang=”java” manual=”%09for%20(int%20i%20%3D%200%3B%20i%20%3C%20vectors.size()%3B%20i%2B%2B)%20%7B%0A%09%09%09%09if%20(bonus.x%20%3D%3D%20vectors.get(i).x%20%26%26%20bonus.y%20%3D%3D%20vectors.get(i).y)%20%7B%0A%0A%09%09%09%09%09bonus%20%3D%20new%20PVector((int)%20random(0%2C%2016)%2C(int)%20random(0%2C%2016))%3B%0A%0A%09%09%09%09%09i%20%3D%200%3B%0A%0A%09%09%09%09%7D%0A%09%09%09%7D” message=”” highlight=”” provider=”manual”/]

W funkcje tej znajduje się też fragment zabezpieczający aby pozycja obiektu “jedzeni” nie była taka sama jak pozycja którego z fragmentów ciała węża. Sprawdzamy czy pozycja jest taka sama jak ogona węża, jeśli tak losujemy nowa pozycję a sprawdzania zaczynamy od nowa i tka do momentu uzyskania właściwej pozycji. Ostatnim elementem jest edycja funkcji draw_stuff i dodanie nowego obiektu.

[pastacode lang=”java” manual=”package%20snakeld%3B%0A%0Aimport%20java.util.ArrayList%3B%0A%0Aimport%20processing.core.PApplet%3B%0Aimport%20processing.core.PVector%3B%0Aimport%20processing.serial.Serial%3B%0A%0Apublic%20class%20SnakeLD%20extends%20PApplet%20%7B%0A%0A%09int%20time_break%20%3D%20200%2C%20start%20%3D%20millis()%2C%20lf%20%3D%2010%2C%20point%20%3D%200%3B%0A%09Serial%20myPort%3B%0A%0A%09String%20com%20%3D%20null%2C%20v%20%3D%20%22DOWN%22%3B%0A%09ArrayList%3CPVector%3E%20vectors%20%3D%20new%20ArrayList%3CPVector%3E()%3B%0A%09PVector%20bonus%20%3D%20new%20PVector(5%2C%205)%3B%0A%0A%09public%20static%20void%20main(String%20_args%5B%5D)%20%7B%0A%09%09PApplet.main(new%20String%5B%5D%20%7B%20SnakeLD.class.getName()%20%7D)%3B%0A%09%7D%0A%0A%09void%20border()%20%7B%0A%09%09if%20(vectors.get(0).x%20%3E%2017)%20%7B%0A%09%09%09vectors.get(0).x%20%3D%200%3B%0A%09%09%7D%0A%09%09if%20(vectors.get(0).x%20%3C%200)%20%7B%0A%09%09%09vectors.get(0).x%20%3D%2017%3B%0A%09%09%7D%0A%0A%09%09if%20(vectors.get(0).y%20%3E%2017)%20%7B%0A%09%09%09vectors.get(0).y%20%3D%200%3B%0A%09%09%7D%0A%09%09if%20(vectors.get(0).y%20%3C%200)%20%7B%0A%09%09%09vectors.get(0).y%20%3D%2017%3B%0A%09%09%7D%0A%09%7D%0A%0A%09boolean%20pauses()%20%7B%0A%09%09if%20(millis()%20-%20start%20%3E%3D%20time_break)%20%7B%0A%09%09%09start%20%3D%20millis()%3B%0A%09%09%09return%20true%3B%0A%09%09%7D%20else%20%7B%0A%09%09%09return%20false%3B%0A%09%09%7D%0A%09%7D%0A%0A%09void%20getPoint()%20%7B%0A%09%09if%20(bonus.x%20%3D%3D%20vectors.get(0).x%20%26%26%20bonus.y%20%3D%3D%20vectors.get(0).y)%20%7B%0A%09%09%09point%20%3D%20point%20%2B%201%3B%0A%0A%09%09%09bonus%20%3D%20new%20PVector((int)%20random(0%2C%2016)%2C%20(int)%20random(0%2C%2016))%3B%0A%0A%09%09%09for%20(int%20i%20%3D%200%3B%20i%20%3C%20vectors.size()%3B%20i%2B%2B)%20%7B%0A%09%09%09%09if%20(bonus.x%20%3D%3D%20vectors.get(i).x%20%26%26%20bonus.y%20%3D%3D%20vectors.get(i).y)%20%7B%0A%0A%09%09%09%09%09bonus%20%3D%20new%20PVector((int)%20random(0%2C%2016)%2C%0A%09%09%09%09%09%09%09(int)%20random(0%2C%2016))%3B%0A%0A%09%09%09%09%09i%20%3D%200%3B%0A%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%0A%09%09%09vectors.add(new%20PVector(vectors.get(vectors.size()%20-%201).x%2C%20vectors%0A%09%09%09%09%09.get(vectors.size()%20-%201).y))%3B%0A%09%09%7D%0A%09%7D%0A%0A%09public%20void%20keybord()%20%7B%0A%0A%09%09while%20(myPort.available()%20%3E%200)%20%7B%0A%0A%09%09%09com%20%3D%20myPort.readStringUntil(lf).trim()%3B%0A%0A%09%09%09if%20(com%20!%3D%20null)%20%7B%0A%0A%09%09%09%09if%20(com.equals(%22UP%22))%20%7B%0A%09%09%09%09%09v%20%3D%20%22UP%22%3B%0A%09%09%09%09%7D%0A%09%09%09%09if%20(com.equals(%22DOWN%22))%20%7B%0A%09%09%09%09%09v%20%3D%20%22DOWN%22%3B%0A%09%09%09%09%7D%0A%09%09%09%09if%20(com.equals(%22LEFT%22))%20%7B%0A%09%09%09%09%09v%20%3D%20%22LEFT%22%3B%0A%09%09%09%09%7D%0A%09%09%09%09if%20(com.equals(%22RIGHT%22))%20%7B%0A%09%09%09%09%09v%20%3D%20%22RIGHT%22%3B%0A%09%09%09%09%7D%0A%09%09%09%09if%20(com.equals(%22ENTER%22))%20%7B%0A%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%09%09%7D%0A%09%7D%0A%0A%09void%20moveLoop()%20%7B%0A%09%09if%20(v%20%3D%3D%20%22UP%22)%20%7B%0A%09%09%09vectors.add(0%2C%20new%20PVector(vectors.get(0).x%2C%20vectors.get(0).y%20-%201))%3B%0A%09%09%09vectors.remove(vectors.size()%20-%201)%3B%0A%09%09%7D%0A%09%09if%20(v%20%3D%3D%20%22DOWN%22)%20%7B%0A%09%09%09vectors.add(0%2C%20new%20PVector(vectors.get(0).x%2C%20vectors.get(0).y%20%2B%201))%3B%0A%09%09%09vectors.remove(vectors.size()%20-%201)%3B%0A%09%09%7D%0A%09%09if%20(v%20%3D%3D%20%22LEFT%22)%20%7B%0A%09%09%09vectors.add(0%2C%20new%20PVector(vectors.get(0).x%20-%201%2C%20vectors.get(0).y))%3B%0A%09%09%09vectors.remove(vectors.size()%20-%201)%3B%0A%09%09%7D%0A%09%09if%20(v%20%3D%3D%20%22RIGHT%22)%20%7B%0A%09%09%09vectors.add(0%2C%20new%20PVector(vectors.get(0).x%20%2B%201%2C%20vectors.get(0).y))%3B%0A%09%09%09vectors.remove(vectors.size()%20-%201)%3B%0A%09%09%7D%0A%09%7D%0A%0A%09void%20draw_stuff()%20%7B%0A%09%09noStroke()%3B%0A%09%09background(255)%3B%0A%0A%09%09for%20(int%20i%20%3D%20vectors.size()%20-%201%3B%20i%20%3E%3D%200%3B%20i–)%20%7B%0A%09%09%09if%20(i%20%3D%3D%200)%20%7B%0A%09%09%09%09fill(0%2C%20255%2C%200)%3B%0A%09%09%09%7D%20else%20%7B%0A%09%09%09%09fill(0%2C%200%2C%20255)%3B%0A%09%09%09%7D%0A%0A%09%09%09rect(vectors.get(i).x%20*%2032%2C%20vectors.get(i).y%20*%2032%2C%2032%2C%2032)%3B%0A%09%09%7D%0A%0A%09%09fill(255%2C%200%2C%200)%3B%0A%09%09rect(bonus.x%20*%2032%2C%20bonus.y%20*%2032%2C%2032%2C%2032)%3B%0A%09%7D%0A%0A%09public%20void%20settings()%20%7B%0A%09%09size(576%2C%20576)%3B%20%2F%2F%20576%20x%20576%0A%09%7D%0A%0A%09public%20void%20setup()%20%7B%0A%09%09color(123%2C%200%2C%200)%3B%0A%09%09vectors.add(new%20PVector(0%2C%202))%3B%0A%09%09vectors.add(new%20PVector(0%2C%201))%3B%0A%09%09vectors.add(new%20PVector(0%2C%200))%3B%0A%09%09myPort%20%3D%20new%20Serial(this%2C%20Serial.list()%5B0%5D%2C%209600)%3B%0A%09%09myPort.clear()%3B%0A%0A%09%7D%0A%0A%09public%20void%20draw()%20%7B%0A%0A%09%09keybord()%3B%0A%0A%09%09if%20(pauses())%20%7B%0A%09%09%09moveLoop()%3B%0A%09%09%7D%0A%0A%09%09getPoint()%3B%0A%09%09border()%3B%0A%0A%09%09draw_stuff()%3B%0A%0A%09%7D%0A%7D” message=”” highlight=”” provider=”manual”/]

(Jeżeli coś wydało wam się nie zrozumiałe lub nie dokładnie opisane zachęcam do komentarzy i pytań, w przyszłości mam pomysł na kilka podobnych projektów gier, jeśli więc jesteście zainteresowani tym tematem ważne jest aby już na początku zrozumieć jak jak najwięcej).

Pod temat czwarty:
Kolizje

Kolizje są ważnym elementem każdej gry, ich działanie jest bardzo proste i bardzo proste do wytłumaczenia. Jest to funkcja lub system mający wykryć kiedy zachodzi jakaś integracja jednego obiektu z innym. W naszym projekcie interesowała nas będzie kolizja węża z samym sobą – czyli moment w którym dojdzie do zderzenia głowy z ogonem.

[pastacode lang=”java” manual=”%09boolean%20moved%20%3D%20false%2C%20game%20%3D%20true%3B%20%0A” message=”” highlight=”” provider=”manual”/]

Na początku dodamy dwie nowe zmienne bool określające status gry (rozgrywka trwa / koniec rozgrywki) oraz druga określająca czy dokonano zmiany położenia (wykonano jakiś ruch).

Tym razem nie będziemy korzystać z nowej funkcji a zajmiemy się edycją już istniejącej.

[pastacode lang=”java” manual=”public%20void%20keybord()%20%7B%0A%0A%09%09while%20(myPort.available()%20%3E%200)%20%7B%0A%0A%09%09%09com%20%3D%20myPort.readStringUntil(lf).trim()%3B%0A%0A%09%09%09if%20(com%20!%3D%20null)%20%7B%0A%0A%09%09%09%09if%20(com.equals(%22UP%22)%20%26%26%20v%20!%3D%20%22DOWN%22%20%26%26%20v%20!%3D%20%22UP%22%20%26%26%20!moved)%20%7B%0A%09%09%09%09%09v%20%3D%20%22UP%22%3B%0A%09%09%09%09%09moved%20%3D%20true%3B%0A%09%09%09%09%7D%0A%09%09%09%09if%20(com.equals(%22DOWN%22)%20%26%26%20v%20!%3D%20%22UP%22%20%26%26%20v%20!%3D%20%22DOWN%22%20%26%26%20!moved)%20%7B%0A%09%09%09%09%09v%20%3D%20%22DOWN%22%3B%0A%09%09%09%09%09moved%20%3D%20true%3B%0A%09%09%09%09%7D%0A%09%09%09%09if%20(com.equals(%22LEFT%22)%20%26%26%20v%20!%3D%20%22RIGHT%22%20%26%26%20v%20!%3D%20%22LEFT%22%20%26%26%20!moved)%20%7B%0A%09%09%09%09%09v%20%3D%20%22LEFT%22%3B%0A%09%09%09%09%09moved%20%3D%20true%3B%0A%09%09%09%09%7D%0A%09%09%09%09if%20(com.equals(%22RIGHT%22)%20%26%26%20v%20!%3D%20%22LEFT%22%20%26%26%20v%20!%3D%20%22RIGHT%22%0A%09%09%09%09%09%09%26%26%20!moved)%20%7B%0A%09%09%09%09%09v%20%3D%20%22RIGHT%22%3B%0A%09%09%09%09%09moved%20%3D%20true%3B%0A%09%09%09%09%7D%0A%09%09%09%09if%20(com.equals(%22ENTER%22))%20%7B%20%2F%2F%20space%20bar%0A%09%09%09%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%09%09%7D%0A%09%7D” message=”” highlight=”” provider=”manual”/]

W tej aktualizacji zlikwidowane zostały czy problemy z do tych czasowym systemem poruszania.
– jeśli poruszamy się w danym kierunku np w lewo nie dokujemy żadnej reakcji jeśli użytkownik po raz kolejny będzie chciał się poruszać w tym kierunku.
– jeśli poruszamy się w danym kierunku np w prawo zablokowana została zmiana kierunku poruszania się w stronę przeciwną w tym wypadku w lewo.
– wyeliminowana został możliwość poruszania się w miejscu, dzięki zmiennej moved, zmiana kierunku poruszania możliwa jest tylko po uprzednim wykonaniu jednego ruchu ( w tym celu edycja obejmuje także funkcje moveLoop()).

[pastacode lang=”java” manual=”void%20colision()%20%7B%0A%0A%09%09for%20(int%20i%20%3D%201%3B%20i%20%3C%20vectors.size()%3B%20i%2B%2B)%20%7B%0A%0A%09%09%09if%20(vectors.get(i).x%20%3D%3D%20vectors.get(0).x%0A%09%09%09%09%09%26%26%20vectors.get(i).y%20%3D%3D%20vectors.get(0).y)%20%7B%0A%09%09%09%09game%20%3D%20!game%3B%0A%09%09%09%7D%0A%09%09%7D%0A%09%7D” message=”” highlight=”” provider=”manual”/]

Ostatnim elementem jest dodanie funkcji sprawdzającej czy zaszła kolizja z samym sobą a jeśli tak nastąpi zmiana statusy gry czyli koniec rozgrywki.

[pastacode lang=”java” manual=”%09if%20(com.equals(%22ENTER%22))%20%7B%20%0A%09%09%09%09%09vectors.clear()%3B%20%2F%2F%20czy%C5%9Bcimy%20wketor%20%0A%09%09%09%09%09vectors.add(new%20PVector(0%2C%202))%3B%20%2F%2F%20doajmey%203%20pocz%C4%85tkowe%20cz%C4%99%C5%9Bci%20cia%C5%82a%0A%09%09%09%09%09vectors.add(new%20PVector(0%2C%201))%3B%0A%09%09%09%09%09vectors.add(new%20PVector(0%2C%200))%3B%0A%09%09%09%09%09v%20%3D%20%22DOWN%22%3B%20%2F%2F%20ustawiamy%20kierunek%0A%0A%09%09%09%09%09point%20%3D%200%3B%20%2F%2F%20zerujemy%20ilo%C5%9B%C4%87%20punkt%C3%B3w%0A%09%09%09%09%09game%20%3D%20true%3B%20%2F%2F%20zmiemy%20status%20gry%20ponownie%20na%20aktywn%C4%85%20rozgrywk%C4%99%20%0A%09%09%09%0A%09%09%09%09%7D” message=”” highlight=”” provider=”manual”/]

W tym miejscu warto by także dodać przycisk, restartu dzięki któremu po przegranej (lub w jakimkolwiek dowolnym momencie) zresetujemy grę.

Ostatnim elementem jest aktualizacji pętli głównej gry czyli funkcji draw().

[pastacode lang=”java” manual=”package%20snakeld%3B%0A%0Aimport%20java.util.ArrayList%3B%0A%0Aimport%20processing.core.PApplet%3B%0Aimport%20processing.core.PVector%3B%0Aimport%20processing.serial.Serial%3B%0A%0Apublic%20class%20SnakeLD%20extends%20PApplet%20%7B%0A%0A%09int%20time_break%20%3D%20200%2C%20start%20%3D%20millis()%2C%20lf%20%3D%2010%2C%20point%20%3D%200%3B%0A%09Serial%20myPort%3B%0A%0A%09String%20com%20%3D%20null%2C%20v%20%3D%20%22DOWN%22%3B%0A%09ArrayList%3CPVector%3E%20vectors%20%3D%20new%20ArrayList%3CPVector%3E()%3B%0A%09PVector%20bonus%20%3D%20new%20PVector(5%2C%205)%3B%0A%09boolean%20moved%20%3D%20false%2C%20game%20%3D%20true%3B%20%0A%0A%09public%20static%20void%20main(String%20_args%5B%5D)%20%7B%0A%09%09PApplet.main(new%20String%5B%5D%20%7B%20SnakeLD.class.getName()%20%7D)%3B%0A%09%7D%0A%0A%09void%20border()%20%7B%0A%09%09if%20(vectors.get(0).x%20%3E%2017)%20%7B%0A%09%09%09vectors.get(0).x%20%3D%200%3B%0A%09%09%7D%0A%09%09if%20(vectors.get(0).x%20%3C%200)%20%7B%0A%09%09%09vectors.get(0).x%20%3D%2017%3B%0A%09%09%7D%0A%0A%09%09if%20(vectors.get(0).y%20%3E%2017)%20%7B%0A%09%09%09vectors.get(0).y%20%3D%200%3B%0A%09%09%7D%0A%09%09if%20(vectors.get(0).y%20%3C%200)%20%7B%0A%09%09%09vectors.get(0).y%20%3D%2017%3B%0A%09%09%7D%0A%09%7D%0A%0A%09boolean%20pauses()%20%7B%0A%09%09if%20(millis()%20-%20start%20%3E%3D%20time_break)%20%7B%0A%09%09%09start%20%3D%20millis()%3B%0A%09%09%09return%20true%3B%0A%09%09%7D%20else%20%7B%0A%09%09%09return%20false%3B%0A%09%09%7D%0A%09%7D%0A%09%0A%09void%20colision()%20%7B%0A%0A%09%09for%20(int%20i%20%3D%201%3B%20i%20%3C%20vectors.size()%3B%20i%2B%2B)%20%7B%0A%0A%09%09%09if%20(vectors.get(i).x%20%3D%3D%20vectors.get(0).x%0A%09%09%09%09%09%26%26%20vectors.get(i).y%20%3D%3D%20vectors.get(0).y)%20%7B%0A%09%09%09%09game%20%3D%20!game%3B%0A%09%09%09%7D%0A%09%09%7D%0A%09%7D%0A%0A%09void%20getPoint()%20%7B%0A%09%09if%20(bonus.x%20%3D%3D%20vectors.get(0).x%20%26%26%20bonus.y%20%3D%3D%20vectors.get(0).y)%20%7B%0A%09%09%09point%20%3D%20point%20%2B%201%3B%0A%0A%09%09%09bonus%20%3D%20new%20PVector((int)%20random(0%2C%2016)%2C%20(int)%20random(0%2C%2016))%3B%0A%0A%09%09%09for%20(int%20i%20%3D%200%3B%20i%20%3C%20vectors.size()%3B%20i%2B%2B)%20%7B%0A%09%09%09%09if%20(bonus.x%20%3D%3D%20vectors.get(i).x%20%26%26%20bonus.y%20%3D%3D%20vectors.get(i).y)%20%7B%0A%0A%09%09%09%09%09bonus%20%3D%20new%20PVector((int)%20random(0%2C%2016)%2C%0A%09%09%09%09%09%09%09(int)%20random(0%2C%2016))%3B%0A%0A%09%09%09%09%09i%20%3D%200%3B%0A%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%0A%09%09%09vectors.add(new%20PVector(vectors.get(vectors.size()%20-%201).x%2C%20vectors%0A%09%09%09%09%09.get(vectors.size()%20-%201).y))%3B%0A%09%09%7D%0A%09%7D%0A%0A%09public%20void%20keybord()%20%7B%0A%0A%09%09while%20(myPort.available()%20%3E%200)%20%7B%0A%0A%09%09%09com%20%3D%20myPort.readStringUntil(lf).trim()%3B%0A%0A%09%09%09if%20(com%20!%3D%20null)%20%7B%0A%0A%09%09%09%09if%20(com.equals(%22UP%22)%20%26%26%20v%20!%3D%20%22DOWN%22%20%26%26%20v%20!%3D%20%22UP%22%20%26%26%20!moved)%20%7B%0A%09%09%09%09%09v%20%3D%20%22UP%22%3B%0A%09%09%09%09%09moved%20%3D%20true%3B%0A%09%09%09%09%7D%0A%09%09%09%09if%20(com.equals(%22DOWN%22)%20%26%26%20v%20!%3D%20%22UP%22%20%26%26%20v%20!%3D%20%22DOWN%22%20%26%26%20!moved)%20%7B%0A%09%09%09%09%09v%20%3D%20%22DOWN%22%3B%0A%09%09%09%09%09moved%20%3D%20true%3B%0A%09%09%09%09%7D%0A%09%09%09%09if%20(com.equals(%22LEFT%22)%20%26%26%20v%20!%3D%20%22RIGHT%22%20%26%26%20v%20!%3D%20%22LEFT%22%20%26%26%20!moved)%20%7B%0A%09%09%09%09%09v%20%3D%20%22LEFT%22%3B%0A%09%09%09%09%09moved%20%3D%20true%3B%0A%09%09%09%09%7D%0A%09%09%09%09if%20(com.equals(%22RIGHT%22)%20%26%26%20v%20!%3D%20%22LEFT%22%20%26%26%20v%20!%3D%20%22RIGHT%22%0A%09%09%09%09%09%09%26%26%20!moved)%20%7B%0A%09%09%09%09%09v%20%3D%20%22RIGHT%22%3B%0A%09%09%09%09%09moved%20%3D%20true%3B%0A%09%09%09%09%7D%0A%09%09%09%09if%20(com.equals(%22ENTER%22))%20%7B%20%0A%09%09%09%09%09vectors.clear()%3B%0A%09%09%09%09%09vectors.add(new%20PVector(0%2C%202))%3B%0A%09%09%09%09%09vectors.add(new%20PVector(0%2C%201))%3B%0A%09%09%09%09%09vectors.add(new%20PVector(0%2C%200))%3B%0A%09%09%09%09%09v%20%3D%20%22DOWN%22%3B%0A%0A%09%09%09%09%09point%20%3D%200%3B%0A%09%09%09%09%09game%20%3D%20true%3B%0A%09%09%09%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%09%09%7D%0A%09%7D%0A%0A%09void%20moveLoop()%20%7B%0A%09%09if%20(v%20%3D%3D%20%22UP%22)%20%7B%0A%09%09%09vectors.add(0%2C%20new%20PVector(vectors.get(0).x%2C%20vectors.get(0).y%20-%201))%3B%0A%09%09%09vectors.remove(vectors.size()%20-%201)%3B%0A%09%09%09moved%20%3D%20false%3B%0A%09%09%7D%0A%09%09if%20(v%20%3D%3D%20%22DOWN%22)%20%7B%0A%09%09%09vectors.add(0%2C%20new%20PVector(vectors.get(0).x%2C%20vectors.get(0).y%20%2B%201))%3B%0A%09%09%09vectors.remove(vectors.size()%20-%201)%3B%0A%09%09%09moved%20%3D%20false%3B%0A%09%09%7D%0A%09%09if%20(v%20%3D%3D%20%22LEFT%22)%20%7B%0A%09%09%09vectors.add(0%2C%20new%20PVector(vectors.get(0).x%20-%201%2C%20vectors.get(0).y))%3B%0A%09%09%09vectors.remove(vectors.size()%20-%201)%3B%0A%09%09%09moved%20%3D%20false%3B%0A%09%09%7D%0A%09%09if%20(v%20%3D%3D%20%22RIGHT%22)%20%7B%0A%09%09%09vectors.add(0%2C%20new%20PVector(vectors.get(0).x%20%2B%201%2C%20vectors.get(0).y))%3B%0A%09%09%09vectors.remove(vectors.size()%20-%201)%3B%0A%09%09%09moved%20%3D%20false%3B%0A%09%09%7D%0A%09%7D%0A%0A%09void%20draw_stuff()%20%7B%0A%09%09noStroke()%3B%0A%09%09background(255)%3B%0A%0A%09%09for%20(int%20i%20%3D%20vectors.size()%20-%201%3B%20i%20%3E%3D%200%3B%20i–)%20%7B%0A%09%09%09if%20(i%20%3D%3D%200)%20%7B%0A%09%09%09%09fill(0%2C%20255%2C%200)%3B%0A%09%09%09%7D%20else%20%7B%0A%09%09%09%09fill(0%2C%200%2C%20255)%3B%0A%09%09%09%7D%0A%0A%09%09%09rect(vectors.get(i).x%20*%2032%2C%20vectors.get(i).y%20*%2032%2C%2032%2C%2032)%3B%0A%09%09%7D%0A%0A%09%09fill(255%2C%200%2C%200)%3B%0A%09%09rect(bonus.x%20*%2032%2C%20bonus.y%20*%2032%2C%2032%2C%2032)%3B%0A%09%7D%0A%0A%09public%20void%20settings()%20%7B%0A%09%09size(576%2C%20576)%3B%20%2F%2F%20576%20x%20576%0A%09%7D%0A%0A%09public%20void%20setup()%20%7B%0A%09%09color(123%2C%200%2C%200)%3B%0A%09%09vectors.add(new%20PVector(0%2C%202))%3B%0A%09%09vectors.add(new%20PVector(0%2C%201))%3B%0A%09%09vectors.add(new%20PVector(0%2C%200))%3B%0A%09%09myPort%20%3D%20new%20Serial(this%2C%20Serial.list()%5B0%5D%2C%209600)%3B%0A%09%09myPort.clear()%3B%0A%0A%09%7D%0A%0A%09public%20void%20draw()%20%7B%0A%0A%0A%09%09keybord()%3B%0A%0A%09%09if%20(game)%20%7B%0A%09%09%09if%20(pauses())%20%7B%0A%09%09%09%09moveLoop()%3B%0A%09%09%09%7D%0A%0A%09%09%09border()%3B%0A%09%09%09getPoint()%3B%0A%0A%09%09%09color(0)%3B%20%0A%09%09%09draw_stuff()%3B%0A%0A%09%09%7D%20else%20%7B%0A%09%09%0A%09%09%7D%0A%0A%09%09myPort.clear()%3B%0A%09%09delay(100)%3B%0A%09%7D%0A%0A%7D” message=”” highlight=”” provider=”manual”/]

(Jeżeli coś wydało wam się nie zrozumiałe lub nie dokładnie opisane zachęcam do komentarzy i pytań, w przyszłości mam pomysł na kilka podobnych projektów gier, jeśli więc jesteście zainteresowani tym tematem ważne jest aby już na początku zrozumieć jak jak najwięcej).

Pod temat piąty:
Detale

Nasza gra wygląda już jak prawdziwa gra i właściwie projekt można by zakończyć w tym miejscu. Jest jednak jeszcze kilka możliwości dzięki którym możemy uczynić swoją grę bardziej atrakcyjną co nie będzie miało wpływu na rozgrywkę ale będzie miało wpływ na odbiór produkcji przez użytkownika.

Jednym z ważniejszych elementów gier w dzisiejszym świecie jest grafika, co prawda w naszym projekcie nie  mamy za dużego pola do popisu ale zawsze możemy coś zmienić. Jak wiadomo w naszej grze za grafikę odpowiedzialna jest funkcja draw_stuff a poprzez kilka prostych zmian w jej budowie możemy już uzyskać ciekawy efekt.

[pastacode lang=”java” manual=”oid%20draw_stuff(int%20b_r%2C%20int%20b_g%2C%20int%20b_b%2C%20int%20h_r%2C%20int%20h_g%2C%20int%20h_b%2C%0A%09%09%09int%20t_r%2C%20int%20t_g%2C%20int%20t_b%2C%20int%20p_r%2C%20int%20p_g%2C%20int%20p_b)%20%7B%0A%09%09noStroke()%3B%0A%09%09background(b_r%2C%20b_g%2C%20b_b)%3B%0A%0A%09%09for%20(int%20i%20%3D%20vectors.size()%20-%201%3B%20i%20%3E%3D%200%3B%20i–)%20%7B%0A%09%09%09if%20(i%20%3D%3D%200)%20%7B%0A%09%09%09%09fill(h_r%2C%20h_g%2C%20h_b)%3B%0A%09%09%09%7D%20else%20%7B%0A%09%09%09%09fill(t_r%2C%20t_g%2C%20t_b)%3B%0A%09%09%09%7D%0A%0A%09%09%09rect(vectors.get(i).x%20*%2032%2C%20vectors.get(i).y%20*%2032%2C%2032%2C%2032)%3B%0A%09%09%7D%0A%0A%09%09fill(p_r%2C%20p_g%2C%20p_b)%3B%0A%09%09rect(bonus.x%20*%2032%2C%20bonus.y%20*%2032%2C%2032%2C%2032)%3B%0A%09%7D” message=”” highlight=”” provider=”manual”/]

Rozbudowaliśmy naszą funkcję o możliwość wprowadzania danych w standardzie RGB dzięki czemu łatwiej będziemy mogli zarządzać kolorami. Zmienioną funkcję możemy teraz zastosować np do zmiany koloru kiedy gracz zakończy rozgrywkę.

Innym detalem jaki warto dodać jest system wyników. Na razie nie musi on być rozbudowany, na początek wystarczy że użytkownik będzie mógł sprawdzić swój rekord w rozgrywce.

Zaczynamy od dodania nowej zmiennej max_score, w której przechowywany będzie aktualny rekord.

[pastacode lang=”java” manual=”%09int%20time_break%20%3D%20200%2C%20start%20%3D%20millis()%2C%20lf%20%3D%2010%2C%20point%20%3D%200%2C%20max_score%20%3D%200%3B” message=”” highlight=”” provider=”manual”/]

Aktualizację rekordu umieszczamy w funkcji w keybord() przy klawiszy “Enter”. Wynik porównujemy z rekordem jeśli gracz kończy jedną nową rozgrywkę a zaczyna kolejną czyli w momencie wciśnięcia przycisku reset (w naszym przypadku przycisk “enter” na pilocie).

Ostatnim etapem jest wyświetlanie rekordu oraz aktualnego wyniku po zakończonej rozgrywce. Wszystkie te elementy odbywać się będę w funkcji draw(), ale zanim jeszcze do tego przejdziemy konieczne jest ustawienie odpowiedniej czcionki, wielkości i koloru tekstu w funkcji setup().

[pastacode lang=”java” manual=”%09%09textFont(createFont(%22Arial%22%2C%2064%2C%20true))%3B” message=”” highlight=”” provider=”manual”/]

Czcionka: Ariel
Wielkość czcionki: 64
Gładkie litery: Tak

[pastacode lang=”java” manual=”public%20void%20draw()%20%7B%0A%0A%09%09keybord()%3B%0A%0A%09%09if%20(game)%20%7B%0A%09%09%09if%20(pauses())%20%7B%0A%09%09%09%09moveLoop()%3B%0A%09%09%09%7D%0A%0A%09%09%09colision()%3B%0A%0A%09%09%09border()%3B%0A%09%09%09getPoint()%3B%0A%0A%09%09%09%2F%2F%20background%20r%20g%20b%0A%09%09%09%2F%2F%20head%20r%20g%20b%0A%09%09%09%2F%2F%20body%20r%20g%20b%0A%09%09%09%2F%2F%20point%20r%20g%20b%0A%0A%09%09%09color(0)%3B%20%2F%2F%20clear%0A%09%09%09draw_stuff(204%2C%20255%2C%20153%2C%20204%2C%20102%2C%200%2C%200%2C%20153%2C%200%2C%20153%2C%200%2C%200)%3B%0A%0A%09%09%09%2F%2F%20white%0A%09%09%09%2F%2F%20blue%0A%09%09%09%2F%2F%20green%0A%09%09%09%2F%2F%20red%0A%0A%09%09%7D%20else%20%7B%0A%09%09%09color(0)%3B%20%2F%2F%20clear%0A%09%09%09draw_stuff(229%2C%20204%2C%20255%2C%20153%2C%20204%2C%20204%2C%20229%2C%20255%2C%20255%2C%20255%2C%20255%2C%0A%09%09%09%09%09102)%3B%0A%0A%09%09%09fill(255%2C%20128%2C%200)%3B%0A%09%09%09textAlign(CENTER%2C%20TOP)%3B%0A%09%09%09text(%22Best%20Score%3A%22%20%2B%20max_score%2C%20288%2C%20200)%3B%0A%09%09%09textAlign(CENTER%2C%20BOTTOM)%3B%0A%09%09%09text(%22Your%20Score%3A%22%20%2B%20point%2C%20288%2C%20400)%3B%0A%0A%09%09%09%2F%2F%20red%0A%09%09%09%2F%2F%20blue%0A%09%09%09%2F%2F%20purple%0A%09%09%09%2F%2F%20blue%0A%09%09%7D%0A%0A%09%09delay(100)%3B%0A%09%7D%0A%7D” message=”” highlight=”” provider=”manual”/]

Na koniec wszystkie zmiany wprowadzamy do funkcji draw().
Od teraz nasza gra prezentuje się tak:

A tak prezentuje się zakończona rozgrywka:


Na koniec załączam jeszcze link do naszego githuba gdzie dostępny jest pełny kod gry.

[ECLIPSE PROCESSING] https://github.com/LearnDuino/SnakeLD/blob/master/SnakeLD.java
[Processing IDE] https://github.com/LearnDuino/SnakeLD/blob/master/SnakeP.pde
[Arduino] https://github.com/LearnDuino/SnakeLD/blob/master/Snake%20LD.ino

Poprzednia informacja Wesołych Świąt
Kolejna informacja Budowa drona cz.1

Brak komentarzy

Zostaw odpowiedź

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *