Zatrzymanie gry

Zaczniemy od zaimplementowania opcji wstrzymania gry, po wciśnięciu klawisza spacji. Jest to z pozoru trudne, jednakże tak naprawdę wymaga minimalnych zmian w kodzie. Zrobimy to w ten sposób, że jeżeli gra jest wstrzymana, to po prostu wąż się nie rusza. Modyfikacja kodu jest w tym przypadku stosunkowo prosta, przy założeniu, że do atrybutów klasy Waz dodamy atrybut pauza, który będzie przyjmował wartości prawda lub fałsz.

Zatrzymanie w języku C++

Dodajemy atrybut pauza jako atrybut klasy Waz.

Linia 1. class Waz. Linia 2. otwórz nawias klamrowy. Linia 3. private dwukropek. Linia 4. int liczbaPunktow znak równości 0 średnik. Linia 5. int pozycjaWezaX znak równości 0 średnik. Linia 6. int pozycjaWezaY znak równości 0 średnik. Linia 7. public dwukropek. Linia 8. bool pauza znak równości false średnik. Linia 9. kropka kropka kropka kropka.

Następnie w metodzie przesun(), z klasy Waz wprowadzamy taki warunek, żeby w przypadku ustawienia atrybutu pauza na true, wąż się nie przesuwał.

Można to zrobić w następujący sposób:

Linia 1. void przesun otwórz nawias okrągły bool asterysk watekGrafikiPracuje przecinek bool asterysk watekWazPracuje przecinek Plansza asterysk plansza zamknij nawias okrągły. Linia 2. otwórz nawias klamrowy. Linia 3. while otwórz nawias okrągły asterysk czyGraDziala zamknij nawias okrągły. Linia 4. otwórz nawias klamrowy. Linia 5. if otwórz nawias okrągły pauza zamknij nawias okrągły. Linia 6. otwórz nawias klamrowy. Linia 7. std dwukropek dwukropek this podkreślnik thread dwukropek dwukropek sleep podkreślnik for otwórz nawias okrągły std dwukropek dwukropek chrono dwukropek dwukropek milliseconds otwórz nawias okrągły 1000 zamknij nawias okrągły zamknij nawias okrągły średnik. Linia 8. zamknij nawias klamrowy. Linia 9. else. Linia 10. otwórz nawias klamrowy. Linia 11. while otwórz nawias okrągły asterysk watekGrafikiPracuje zamknij nawias okrągły. Linia 12. otwórz nawias klamrowy. Linia 13. std dwukropek dwukropek this podkreślnik thread dwukropek dwukropek sleep podkreślnik for otwórz nawias okrągły std dwukropek dwukropek chrono dwukropek dwukropek milliseconds otwórz nawias okrągły 1000 zamknij nawias okrągły zamknij nawias okrągły średnik. Linia 14. zamknij nawias klamrowy. Linia 15. asterysk watekWazPracuje znak równości true średnik. Linia 16. if otwórz nawias okrągły kierunekRuchu znak równości znak równości polnoc zamknij nawias okrągły. Linia 17. otwórz nawias klamrowy. Linia 18. pozycjaWezaY minus znak równości 1 średnik. Linia 19. zamknij nawias klamrowy. Linia 20. else if otwórz nawias okrągły kierunekRuchu znak równości znak równości poludnie zamknij nawias okrągły. Linia 21. otwórz nawias klamrowy. Linia 22. pozycjaWezaY plus znak równości 1 średnik. Linia 23. zamknij nawias klamrowy. Linia 24. else if otwórz nawias okrągły kierunekRuchu znak równości znak równości zachod zamknij nawias okrągły. Linia 25. otwórz nawias klamrowy. Linia 26. pozycjaWezaX plus znak równości 1 średnik. Linia 27. zamknij nawias klamrowy. Linia 28. else if otwórz nawias okrągły kierunekRuchu znak równości znak równości wschod zamknij nawias okrągły. Linia 29. otwórz nawias klamrowy. Linia 30. pozycjaWezaX minus znak równości 1 średnik. Linia 31. zamknij nawias klamrowy. Linia 32. asterysk watekWazPracuje znak równości false średnik. Linia 33. Owoc asterysk owocNaPolu znak równości ampersant plansza minus zamknij nawias ostrokątny pole otwórz nawias kwadratowy pozycjaWezaY zamknij nawias kwadratowy otwórz nawias kwadratowy pozycjaWezaX zamknij nawias kwadratowy kropka owoc średnik. Linia 34. if otwórz nawias okrągły sprawdzPozycjeY otwórz nawias okrągły zamknij nawias okrągły otwórz nawias ostrokątny 0 kreska pionowa kreska pionowa sprawdzPozycjeY otwórz nawias okrągły zamknij nawias okrągły zamknij nawias ostrokątny plansza minus zamknij nawias ostrokątny rozmiarYPlanszy. Linia 35. kreska pionowa kreska pionowa sprawdzPozycjeX otwórz nawias okrągły zamknij nawias okrągły otwórz nawias ostrokątny 0 kreska pionowa kreska pionowa sprawdzPozycjeX otwórz nawias okrągły zamknij nawias okrągły zamknij nawias ostrokątny plansza minus zamknij nawias ostrokątny rozmiarXPlanszy zamknij nawias okrągły. Linia 36. otwórz nawias klamrowy prawy ukośnik prawy ukośnik waz wyjezdza poza mape. Linia 37. asterysk czyGraDziala znak równości false średnik. Linia 38. break średnik. Linia 39. zamknij nawias klamrowy. Linia 40. if otwórz nawias okrągły owocNaPolu minus zamknij nawias ostrokątny sprawdzPunkty otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły. Linia 41. otwórz nawias klamrowy. Linia 42. zjedzOwoc otwórz nawias okrągły owocNaPolu przecinek plansza zamknij nawias okrągły średnik. Linia 43. if otwórz nawias okrągły plansza minus zamknij nawias ostrokątny liczbaOwocow znak równości znak równości 0 zamknij nawias okrągły prawy ukośnik prawy ukośnik wszystkie owoce zjedzone. Linia 44. otwórz nawias klamrowy. Linia 45. asterysk czyGraDziala znak równości false średnik. Linia 46. zamknij nawias klamrowy. Linia 47. zamknij nawias klamrowy. Linia 48. if otwórz nawias okrągły plansza minus zamknij nawias ostrokątny pole otwórz nawias kwadratowy pozycjaWezaY zamknij nawias kwadratowy otwórz nawias kwadratowy pozycjaWezaX zamknij nawias kwadratowy kropka wartoscPola zamknij nawias ostrokątny 0 zamknij nawias okrągły prawy ukośnik prawy ukośnik waz dotyka swojego ogona. Linia 49. asterysk czyGraDziala znak równości false średnik. Linia 50. plansza minus zamknij nawias ostrokątny zaaktualizujOgonWeza otwórz nawias okrągły zamknij nawias okrągły średnik. Linia 51. plansza minus zamknij nawias ostrokątny pole otwórz nawias kwadratowy pozycjaWezaY zamknij nawias kwadratowy otwórz nawias kwadratowy pozycjaWezaX zamknij nawias kwadratowy kropka wartoscPola znak równości liczbaPunktow plus 1 średnik. Linia 52. std dwukropek dwukropek this podkreślnik thread dwukropek dwukropek sleep podkreślnik for otwórz nawias okrągły std dwukropek dwukropek chrono dwukropek dwukropek milliseconds otwórz nawias okrągły 400 zamknij nawias okrągły zamknij nawias okrągły średnik. Linia 53. zamknij nawias klamrowy. Linia 54. zamknij nawias klamrowy. Linia 55. zamknij nawias klamrowy.

Teraz wystarczy zaimplementować opcję, która pozwoli, by kliknięcie klawisza spacja zmieniało wartość atrybutu pauza z prawdy na fałsz i z fałszu na prawdę.

Linia 1. class ObslugaWejscia. Linia 2. otwórz nawias klamrowy. Linia 3. public dwukropek. Linia 4. bool asterysk czyGraDziala średnik. Linia 5. void zinterpretujWcisnietyPrzycisk otwórz nawias okrągły Waz asterysk waz zamknij nawias okrągły. Linia 6. otwórz nawias klamrowy. Linia 7. while otwórz nawias okrągły asterysk czyGraDziala zamknij nawias okrągły. Linia 8. otwórz nawias klamrowy. Linia 9. char przycisk znak równości 0 średnik. Linia 10. if otwórz nawias okrągły kbhit otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły. Linia 11. przycisk znak równości getch otwórz nawias okrągły zamknij nawias okrągły średnik. Linia 12. switch otwórz nawias okrągły przycisk zamknij nawias okrągły. Linia 13. otwórz nawias klamrowy. Linia 14. case apostrof a apostrof dwukropek. Linia 15. if otwórz nawias okrągły waz minus zamknij nawias ostrokątny kierunekRuchu znak równości znak równości waz minus zamknij nawias ostrokątny polnoc zamknij nawias okrągły. Linia 16. waz minus zamknij nawias ostrokątny kierunekRuchu znak równości waz minus zamknij nawias ostrokątny zachod średnik. Linia 17. else if otwórz nawias okrągły waz minus zamknij nawias ostrokątny kierunekRuchu znak równości znak równości waz minus zamknij nawias ostrokątny wschod zamknij nawias okrągły. Linia 18. waz minus zamknij nawias ostrokątny kierunekRuchu znak równości waz minus zamknij nawias ostrokątny polnoc średnik. Linia 19. else if otwórz nawias okrągły waz minus zamknij nawias ostrokątny kierunekRuchu znak równości znak równości waz minus zamknij nawias ostrokątny poludnie zamknij nawias okrągły. Linia 20. waz minus zamknij nawias ostrokątny kierunekRuchu znak równości waz minus zamknij nawias ostrokątny wschod średnik. Linia 21. else. Linia 22. waz minus zamknij nawias ostrokątny kierunekRuchu znak równości waz minus zamknij nawias ostrokątny poludnie średnik. Linia 23. break średnik. Linia 24. case apostrof d apostrof dwukropek. Linia 25. if otwórz nawias okrągły waz minus zamknij nawias ostrokątny kierunekRuchu znak równości znak równości waz minus zamknij nawias ostrokątny polnoc zamknij nawias okrągły. Linia 26. waz minus zamknij nawias ostrokątny kierunekRuchu znak równości waz minus zamknij nawias ostrokątny wschod średnik. Linia 27. else if otwórz nawias okrągły waz minus zamknij nawias ostrokątny kierunekRuchu znak równości znak równości waz minus zamknij nawias ostrokątny zachod zamknij nawias okrągły. Linia 28. waz minus zamknij nawias ostrokątny kierunekRuchu znak równości waz minus zamknij nawias ostrokątny polnoc średnik. Linia 29. else if otwórz nawias okrągły waz minus zamknij nawias ostrokątny kierunekRuchu znak równości znak równości waz minus zamknij nawias ostrokątny poludnie zamknij nawias okrągły. Linia 30. waz minus zamknij nawias ostrokątny kierunekRuchu znak równości waz minus zamknij nawias ostrokątny zachod średnik. Linia 31. else. Linia 32. waz minus zamknij nawias ostrokątny kierunekRuchu znak równości waz minus zamknij nawias ostrokątny poludnie średnik. Linia 33. break średnik. Linia 34. case apostrof apostrof dwukropek. Linia 35. waz minus zamknij nawias ostrokątny pauza znak równości wykrzyknik waz minus zamknij nawias ostrokątny pauza średnik. Linia 36. break średnik. Linia 37. zamknij nawias klamrowy. Linia 38. zamknij nawias klamrowy. Linia 39. zamknij nawias klamrowy. Linia 40. zamknij nawias klamrowy średnik.

Zatrzymanie w języku Java

Zaczniemy od dodania atrybutu pauza do klasy Waz.

Linia 1. public class Waz implements Runnable otwórz nawias klamrowy. Linia 2. public enum Kierunek otwórz nawias klamrowy polnoc przecinek wschod przecinek poludnie przecinek zachod zamknij nawias klamrowy. Linia 3. boolean pauza znak równości false średnik. Linia 4. private int liczbaPunktow znak równości 0 średnik. Linia 5. private int pozycjaWezaX znak równości 0 średnik. Linia 6. private int pozycjaWezaY znak równości 0 średnik. Linia 7. Plansza plansza średnik. Linia 8. boolean czyGraDziala średnik. Linia 9. public Kierunek kierunekRuchu znak równości Kierunek kropka polnoc średnik. Linia 10. kropka kropka kropka.

Następnie w klasie ObslugaWejscia zapiszemy, że klawisz spacja będzie modyfikował atrybut pauza obiektu klasy Waz.

Linia 1. at Override. Linia 2. public void keyPressed otwórz nawias okrągły KeyEvent e zamknij nawias okrągły otwórz nawias klamrowy. Linia 3. char znak znak równości e kropka getKeyChar otwórz nawias okrągły zamknij nawias okrągły średnik. Linia 4. switch otwórz nawias okrągły znak zamknij nawias okrągły otwórz nawias klamrowy. Linia 5. case apostrof a apostrof dwukropek. Linia 6. if otwórz nawias okrągły waz kropka kierunekRuchu znak równości znak równości Waz kropka Kierunek kropka polnoc zamknij nawias okrągły otwórz nawias klamrowy. Linia 7. waz kropka kierunekRuchu znak równości Waz kropka Kierunek kropka zachod średnik. Linia 8. zamknij nawias klamrowy else if otwórz nawias okrągły waz kropka kierunekRuchu znak równości znak równości Waz kropka Kierunek kropka wschod zamknij nawias okrągły otwórz nawias klamrowy. Linia 9. waz kropka kierunekRuchu znak równości Waz kropka Kierunek kropka polnoc średnik. Linia 10. zamknij nawias klamrowy else if otwórz nawias okrągły waz kropka kierunekRuchu znak równości znak równości Waz kropka Kierunek kropka poludnie zamknij nawias okrągły otwórz nawias klamrowy. Linia 11. waz kropka kierunekRuchu znak równości Waz kropka Kierunek kropka wschod średnik. Linia 12. zamknij nawias klamrowy else otwórz nawias klamrowy. Linia 13. waz kropka kierunekRuchu znak równości Waz kropka Kierunek kropka poludnie średnik. Linia 14. zamknij nawias klamrowy. Linia 15. break średnik. Linia 17. case apostrof d apostrof dwukropek. Linia 18. if otwórz nawias okrągły waz kropka kierunekRuchu znak równości znak równości Waz kropka Kierunek kropka polnoc zamknij nawias okrągły otwórz nawias klamrowy. Linia 19. waz kropka kierunekRuchu znak równości Waz kropka Kierunek kropka wschod średnik. Linia 20. zamknij nawias klamrowy else if otwórz nawias okrągły waz kropka kierunekRuchu znak równości znak równości Waz kropka Kierunek kropka zachod zamknij nawias okrągły otwórz nawias klamrowy. Linia 21. waz kropka kierunekRuchu znak równości Waz kropka Kierunek kropka polnoc średnik. Linia 22. zamknij nawias klamrowy else if otwórz nawias okrągły waz kropka kierunekRuchu znak równości znak równości Waz kropka Kierunek kropka poludnie zamknij nawias okrągły otwórz nawias klamrowy. Linia 23. waz kropka kierunekRuchu znak równości Waz kropka Kierunek kropka zachod średnik. Linia 24. zamknij nawias klamrowy else otwórz nawias klamrowy. Linia 25. waz kropka kierunekRuchu znak równości Waz kropka Kierunek kropka poludnie średnik. Linia 26. zamknij nawias klamrowy. Linia 27. break średnik. Linia 28. case apostrof apostrof dwukropek. Linia 29. waz kropka pauza znak równości wykrzyknik waz kropka pauza średnik. Linia 30. break średnik. Linia 31. zamknij nawias klamrowy. Linia 32. zamknij nawias klamrowy.

Na koniec w metodzie run
()
, będziemy przesuwać węża tylko wtedy, gdy atrybut pauza jest ustawiony na fałsz.

Linia 1. at Override. Linia 2. public void run otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy. Linia 3. while otwórz nawias okrągły czyGraDziala zamknij nawias okrągły otwórz nawias klamrowy. Linia 4. try otwórz nawias klamrowy. Linia 5. Thread kropka sleep otwórz nawias okrągły 1000 zamknij nawias okrągły średnik. Linia 6. zamknij nawias klamrowy catch otwórz nawias okrągły InterruptedException e zamknij nawias okrągły otwórz nawias klamrowy. Linia 7. e kropka printStackTrace otwórz nawias okrągły zamknij nawias okrągły średnik. Linia 8. zamknij nawias klamrowy. Linia 9. if otwórz nawias okrągły wykrzyknik this kropka pauza zamknij nawias okrągły przesun otwórz nawias okrągły zamknij nawias okrągły średnik. Linia 10. if otwórz nawias okrągły wykrzyknik sprawdzCzyNaPlanszy otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy. Linia 11. break średnik. Linia 12. zamknij nawias klamrowy. Linia 13. zamknij nawias klamrowy. Linia 14. zamknij nawias klamrowy.

Zatrzymanie w Pythonie

Tak jak zostało wcześniej omówione, dodajemy atrybut pauza jako atrybut klasy Waz.

Linia 1. class Waz dwukropek. Linia 2. import enum. Linia 3. czyGraDziala znak równości True. Linia 4. class Kierunek otwórz nawias okrągły enum kropka Enum zamknij nawias okrągły dwukropek. Linia 5. polnoc znak równości 0. Linia 6. wschod znak równości 1. Linia 7. poludnie znak równości 2. Linia 8. zachod znak równości 3. Linia 9. pauza znak równości False. Linia 10. kropka kropka kropka kropka.

Następnie modyfikujemy klasę ObslugaWejscia() w ten sposób, żeby zmieniać wartości tego atrybutu, po każdym wciśnięciu przycisku.

Linia 1. class ObslugaWejscia otwórz nawias okrągły zamknij nawias okrągły dwukropek. Linia 2. def zinterpretujWcisnietyPrzycisk otwórz nawias okrągły self przecinek waz zamknij nawias okrągły dwukropek. Linia 3. import msvcrt. Linia 4. while 1 dwukropek. Linia 5. x znak równości msvcrt kropka getch otwórz nawias okrągły zamknij nawias okrągły kropka decode otwórz nawias okrągły apostrof ASCII apostrof zamknij nawias okrągły. Linia 6. if x znak równości znak równości apostrof a apostrof dwukropek. Linia 7. if waz kropka kierunekRuchu znak równości znak równości waz kropka Kierunek kropka polnoc kropka value dwukropek. Linia 8. waz kropka kierunekRuchu znak równości waz kropka Kierunek kropka zachod kropka value. Linia 9. elif waz kropka kierunekRuchu znak równości znak równości waz kropka Kierunek kropka wschod kropka value dwukropek. Linia 10. waz kropka kierunekRuchu znak równości waz kropka Kierunek kropka polnoc kropka value. Linia 11. elif waz kropka kierunekRuchu znak równości znak równości waz kropka Kierunek kropka poludnie kropka value dwukropek. Linia 12. waz kropka kierunekRuchu znak równości waz kropka Kierunek kropka wschod kropka value. Linia 13. elif waz kropka kierunekRuchu znak równości znak równości waz kropka Kierunek kropka zachod kropka value dwukropek. Linia 14. waz kropka kierunekRuchu znak równości waz kropka Kierunek kropka poludnie kropka value. Linia 15. elif x znak równości znak równości apostrof d apostrof dwukropek. Linia 16. if waz kropka kierunekRuchu znak równości znak równości waz kropka Kierunek kropka polnoc kropka value dwukropek. Linia 17. waz kropka kierunekRuchu znak równości waz kropka Kierunek kropka wschod kropka value. Linia 18. elif waz kropka kierunekRuchu znak równości znak równości waz kropka Kierunek kropka wschod kropka value dwukropek. Linia 19. waz kropka kierunekRuchu znak równości waz kropka Kierunek kropka poludnie kropka value. Linia 20. elif waz kropka kierunekRuchu znak równości znak równości waz kropka Kierunek kropka poludnie kropka value dwukropek. Linia 21. waz kropka kierunekRuchu znak równości waz kropka Kierunek kropka zachod kropka value. Linia 22. elif waz kropka kierunekRuchu znak równości znak równości waz kropka Kierunek kropka zachod kropka value dwukropek. Linia 23. waz kropka kierunekRuchu znak równości waz kropka Kierunek kropka polnoc kropka value. Linia 24. elif x znak równości znak równości apostrof apostrof dwukropek. Linia 25. waz kropka pauza znak równości not waz kropka pauza kratka nasza modyfikacja.

Teraz na samym początku metody przesun(), dodajemy:

Linia 1. def przesun otwórz nawias okrągły self przecinek zamekWeza przecinek zamekGrafiki przecinek plansza zamknij nawias okrągły dwukropek. Linia 2. import time. Linia 3. while self kropka czyGraDziala dwukropek. Linia 4. if self kropka pauza dwukropek. Linia 5. time kropka sleep otwórz nawias okrągły 1 zamknij nawias okrągły. Linia 6. continue. Linia 7. kropka kropka kropka kropka.

W tym fragmencie kodu korzystamy ze słowa kluczowego continue, które powoduje, że aktualny przebieg pętli zostaje przerwany, a wątek wraca do jej początku. Nie jest to najefektywniejsze rozwiązanie i wielu programistów zasugeruje, żeby zmianę wprowadzić tak, aby zamiast słowa continue, wykorzystać słowo kluczowe else w instrukcji warunkowej:

Linia 1. def przesun otwórz nawias okrągły self przecinek zamekWeza przecinek zamekGrafiki przecinek plansza zamknij nawias okrągły dwukropek. Linia 2. import time. Linia 3. while self kropka czyGraDziala dwukropek. Linia 4. if self kropka pauza dwukropek. Linia 5. time kropka sleep otwórz nawias okrągły 1 zamknij nawias okrągły. Linia 6. else dwukropek. Linia 7. zamekWeza kropka acquire otwórz nawias okrągły zamknij nawias okrągły. Linia 8. if self kropka kierunekRuchu znak równości znak równości self kropka Kierunek kropka polnoc kropka value dwukropek. Linia 9. self kropka pozycjaWezaY minus znak równości 1. Linia 10. elif self kropka kierunekRuchu znak równości znak równości self kropka Kierunek kropka poludnie kropka value dwukropek. Linia 11. self kropka pozycjaWezaY plus znak równości 1. Linia 12. elif self kropka kierunekRuchu znak równości znak równości self kropka Kierunek kropka zachod kropka value dwukropek. Linia 13. self kropka pozycjaWezaX minus znak równości 1. Linia 14. elif self kropka kierunekRuchu znak równości znak równości self kropka Kierunek kropka wschod kropka value dwukropek. Linia 15. self kropka pozycjaWezaX plus znak równości 1. Linia 16. if plansza kropka ileOwocow znak równości znak równości 0 dwukropek. Linia 17. waz kropka czyGraDziala znak równości False. Linia 18. if self kropka sprawdzPozycjeY otwórz nawias okrągły zamknij nawias okrągły otwórz nawias ostrokątny 0 or self kropka sprawdzPozycjeY otwórz nawias okrągły zamknij nawias okrągły zamknij nawias ostrokątny znak równości plansza kropka rozmiarYPlanszy or self kropka sprawdzPozycjeX otwórz nawias okrągły zamknij nawias okrągły otwórz nawias ostrokątny 0 or self kropka sprawdzPozycjeX otwórz nawias okrągły zamknij nawias okrągły zamknij nawias ostrokątny znak równości plansza kropka rozmiarXPlanszy dwukropek. Linia 19. zamekGrafiki kropka release otwórz nawias okrągły zamknij nawias okrągły. Linia 20. waz kropka czyGraDziala znak równości False. Linia 21. break. Linia 22. else dwukropek. Linia 23. owoc znak równości plansza kropka pole otwórz nawias kwadratowy self kropka sprawdzPozycjeY otwórz nawias okrągły zamknij nawias okrągły zamknij nawias kwadratowy otwórz nawias kwadratowy self kropka sprawdzPozycjeX otwórz nawias okrągły zamknij nawias okrągły zamknij nawias kwadratowy kropka owoc. Linia 24. if owoc wykrzyknik znak równości None dwukropek. Linia 25. self kropka zjedzOwoc otwórz nawias okrągły plansza kropka pole otwórz nawias kwadratowy self kropka sprawdzPozycjeY otwórz nawias okrągły zamknij nawias okrągły zamknij nawias kwadratowy otwórz nawias kwadratowy self kropka sprawdzPozycjeX otwórz nawias okrągły zamknij nawias okrągły zamknij nawias kwadratowy zamknij nawias okrągły. Linia 26. pole znak równości plansza kropka pole otwórz nawias kwadratowy self kropka sprawdzPozycjeY otwórz nawias okrągły zamknij nawias okrągły zamknij nawias kwadratowy otwórz nawias kwadratowy self kropka sprawdzPozycjeX otwórz nawias okrągły zamknij nawias okrągły zamknij nawias kwadratowy. Linia 27. plansza kropka zaaktualizujOgonWeza otwórz nawias okrągły zamknij nawias okrągły. Linia 29. if pole kropka wartoscPola zamknij nawias ostrokątny 0 dwukropek. Linia 30. waz kropka czyGraDziala znak równości False kratka dotkniecie ogona. Linia 31. pole kropka wartoscPola znak równości self kropka liczbaPunktow plus 1. Linia 32. time kropka sleep otwórz nawias okrągły 1 zamknij nawias okrągły. Linia 33. zamekGrafiki kropka release otwórz nawias okrągły zamknij nawias okrągły.

To od ciebie zależy, jaką metodę zastosujesz w swoim projekcie. Zaproponowane rozwiązanie jest czytelniejsze, dzięki czemu działanie pętli łatwiej można przeanalizować, aby wykryć ewentualne błędy.

Ramka

Zaimplementujemy teraz ramki otaczające rozgrywkę. Do dyspozycji mamy tylko tryb tekstowy, nasze możliwości są więc ograniczone. Ramkę możemy wykonać na wiele sposobów, z użyciem różnych wzorów. Z racji tego, że celem ramki jest to, żeby wyglądała estetycznie i funkcjonalnie, nie chcemy narzucać żadnej wizji artystycznej, a jedynie zasugerujemy przykładowe rozwiązanie – wraz z wyjaśnieniem, jak je narysować.

Linia 1. asterysk minus asterysk minus asterysk minus asterysk minus asterysk minus asterysk minus asterysk minus asterysk minus asterysk minus asterysk minus asterysk.

Wzór ten można uzyskać w pseudokodzie w następujący sposób:

Linia 1. dla i znak równości 1 przecinek 2 kropka kropka kropka n wykonuj dwukropek. Linia 2. jeżeli i mod 2 znak równości znak równości 0 dwukropek. Linia 3. wypisz otwórz nawias okrągły cudzysłów minus cudzysłów zamknij nawias okrągły. Linia 4. w przeciwnym razie jeżeli i mod 2 znak równości znak równości 1 dwukropek. Linia 5. wypisz otwórz nawias okrągły cudzysłów asterysk cudzysłów zamknij nawias okrągły.

Wszystkie podobne, cykliczne wzory, uzyskujemy analogicznie:

Linia 1. dla i znak równości 1 przecinek 2 kropka kropka kropka n wykonuj dwukropek. Linia 2. jeżeli i mod LiczbaZnakow znak równości znak równości 1 dwukropek. Linia 3. wypisz otwórz nawias okrągły pierwszyZnaczek zamknij nawias okrągły. Linia 4. w przeciwnym razie jeżeli i mod LiczbaZnakow znak równości znak równości 2 dwukropek. Linia 5. wypisz otwórz nawias okrągły drugiZnaczek zamknij nawias okrągły. Linia 7. kropka kropka kropka kropka. Linia 9. w przeciwnym razie jeżeli i mod LiczbaZnakow znak równości znak równości LiczbaZnakow minus 1. Linia 10. wypisz otwórz nawias okrągły przedostatniZnaczek zamknij nawias okrągły. Linia 11. w przeciwnym razie jeżeli i mod LiczbaZnakow znak równości znak równości 0. Linia 12. wypisz otwórz nawias okrągły ostatniZnaczek zamknij nawias okrągły.

W przytoczonym przykładzie zmienna LiczbaZnakow zawiera informację, z ilu znaków składa się jeden element wzoru. W przypadku ramek poziomych wystarczą dwie takie pętle, na początku i na końcu wyświetlania danej klatki. W przypadku pionowych ramek sprawa jest trochę bardziej złożona, ponieważ musimy wyświetlać je w dobrym miejscu.

To znaczy musimy wyświetlać je w każdej wyświetlanej linijce, przed i po wyświetleniu właściwych pól. W tym celu wystarczy wstawić przed odpowiednimi pętlami (a także po ich zastowaniu) warunki odpowiadające docelowej ramce.

Polecenie 1

Zmodyfikuj grę w ten sposób, żeby pionowo oraz poziomo pojawiała się następująca ramka:

Linia 1. asterysk asterysk minus minus.

Oto zmodyfikowane klasy w C++, Javie i w Pythonie.

W zaprezentowanych rozwiązaniach dodatkowo usunęliśmy wyświetlanie pola znakiem „+”, ponieważ po dodaniu ramki mamy informacje o granicach mapy, a bez wyświetlania poszczególnych komórek, gra jest dużo bardziej estetyczna.

W języku Python , dodatkowo, dla czytelności zmieniliśmy szerokość odstępów pomiędzy poszczególnymi polami, z „\t” na wielokrotną spację.

Całość kodu źródłowego można pobrać, korzystając z linków:

R1WlOtb3m9dfu

Przycisk umożliwiający pobranie pliku Kod źródłowy C++

Kod źródłowy C++
Plik ZIP o rozmiarze 2.21 KB w języku polskim
RehgNqytW44kR

Przycisk umożliwiający pobranie pliku Kod źródłowy Java

Kod źródłowy Java
Plik ZIP o rozmiarze 4.18 KB w języku polskim
R1CoDGSEmgmKv

Przycisk umożliwiający pobranie pliku Plik źródłowy Python

Plik źródłowy Python
Plik ZIP o rozmiarze 1.98 KB w języku polskim

Możliwe modyfikacje

Warto byłoby rozważyć kilka zmian:

  • Zmiana samego wyglądu oraz interfejsu na bardziej współczesny.

  • Dodanie dodatkowych wzmocnień zbieralnych przez węża, np. przyspieszenie, spowolnienie lub danie mu możliwości warunkowego przejścia przez swój ogon.

  • Generowanie stałej liczby owoców podczas uruchamiania gry i ponowne pojawienie się owocu po zjedzeniu.

  • Dodanie dodatkowych trybów rozgrywki, np. trybu turniejowego dla gier imprezowych.

  • Zaimplementowanie funkcji przechodzenia węża przez ściany.

  • Dodanie historii gier wraz z wynikami.

Omówimy kilka z proponowanych tutaj zmian.

Zmiana interfejsu w języku Java

Możemy skorzystać z kilku bibliotek, m.in. z biblioteki SWING oraz JavaFX.

Obie oferują podobny zakres możliwości. Oto ich krótka charakteryzacja:

Swing wchodzi w skład JFC, czyli Java Foundation Classes, biblioteki komponentów graficznego interfejsu użytkownika oraz usług, które z założenia miały ułatwić proces tworzenia aplikacji desktopowych i internetowych. JFC w całości jest rozwiązaniem wieloplatformowym.

Alternatywą jest JavaFX, technologia, której zamysłem było zastąpienie Swing. Jest to potężna biblioteka, umożliwiająca budowanie zaawansowanych gier. Dla JavaFX dostępne są narzędzia, z których pomocą można w prosty sposób zaprojektować interfejs graficzny. Najważniejszym narzędziem tego typu jest SceneBuilder.

Oto przykład prototypu gry utworzonej z użyciem JavaFX:

RePe6HlzH9H3h

Zmiana interfejsu w języku C++

Z racji tego, że projektujemy program przeznaczony na system Windows, możemy skorzystać z Windows Forms, czyli ze szkieletu aplikacji, umożliwiającego proste tworzenie aplikacji. Nie służy on stricte do tworzenia gier, ale do tworzenia aplikacji okienkowych. Istnieje możliwość takiego modyfikowania okienka i jego elementów, by utworzyć pożądany efekt. Nie jest to jednak rozwiązanie optymalne.

W C++ możemy jeszcze spróbować skorzystać z OpenGL, który służy do generowania dowolnego rodzaju grafiki. Do tej technologii polecamy skorzystanie dodatkowo z biblioteki GLUT, dodającej wiele przydatnych elementów. OpenGL jest jednak stosunkowo skomplikowany i ma duży próg wejścia. Ostatecznie, korzystając ze wspomnianej technologii oraz biblioteki, możemy w niej tworzyć grafikę z użyciem kształtów lub pojedynczych prymitywów graficznych. Technologia ta umożliwia tworzenie bardzo zaawansowanych animacji. Dodatkowym problemem tej technologii jest to, że przydatna jest w niej dobra znajomość geometrii. Zaletą OpenGL jest to, że w prosty sposób pozwala utworzyć dla gry warstwę prezentacji z wykorzystaniem grafiki.

Dla zainteresowanych

Do samego OpenGL istnieje dużo bibliotek, oferujących wiele zaawansowanych funkcji. Wymienienie wszystkich jest niemożliwe, dlatego w tym przypadku polecamy zainteresowanie się literaturą związaną z tym tematem.
Spośród nich na szczególne wyróżnienie zasługują biblioteki SDL oraz SFML, które są bardziej rozbudowane niż biblioteka GLUT – nieraz więc nazywa się je prostszymi.

Możemy również skorzystać z gotowych silników gry, kompatybilnych z językiem C++. Przykładem takich silników jest choćby Unreal Engine czy Godot. W silnikach często zaimplementowana jest wielowątkowość, którą sami – na potrzeby gry – musimy wprowadzać. Służą one do produkcji całej gry, a nie tylko do tworzenia warstwy wizualnej.

Ciekawostka

DirectX – podobnie jak OpenGL – jest Interfejsem Programowania Aplikacji (APIAPIAPI). Dzięki temu możemy więc – w uproszczony sposób – generować grafikę. DirectX przeznaczony jest głównie na systemy Windows. Przykładowo, DirectX 12 może być używany jedynie na systemie Windows 10 (albo w nowszej wersji). Swoją popularność w grach zawdzięcza głównie temu, że API jest tworzone przez Microsoft, dzięki czemu posiada kompleksową dokumentację oraz dobrej jakości narzędzia.

Zmiana interfejsu w języku Python

W przypadku Pythona możemy skorzystać z OpenGL. Jest to technologia pozwalająca generować grafikę. W swojej pierwotnej postaci pozwala na generowanie tzw. prymitywów, przez co ma dość wysoki próg wejścia. Do sprawnego posługiwania się nimi wymagana jest zaawansowana znajomość geometrii.

Na pomoc przychodzą jednak biblioteki typu GLUT, zaimplementowane w pakiecie PyOpenGL, a także wspomniana biblioteka PySFML.

GLUT oferuje nam gotowe figury geometryczne, natomiast SFML bardziej złożone konstrukcje. Dodatkową zaletą SFML jest to, że również zaimplementowano ją w języku C++ i Java.

Na omówienie zasługuje również biblioteka PyGame, stworzona z myślą o pisaniu gier w języku Python. Biblioteka ta posiada, podobnie jak inne wymienione, wbudowaną obsługę przechwytywania wciskanych klawiszy, jak również metody pozwalające wczytywać gotowe grafiki.

Generowanie stałej liczby owoców i pojawianie się owoców

Można to zaimplementować na kilka sposobów. Mianowicie:

  • Stworzyć predefiniowane mapy, które będziemy wczytywali, dzięki czemu uzyskamy stałą liczbę owoców. Jest to jednak rozwiązanie dość ograniczone, a jednocześnie pracochłonne. Każdą mapę należy oddzielnie zaprojektować, a ponadto aby rozgrywka była ciekawa, map takich powinno być stosunkowo dużo. W przeciwnym wypadku gra szybko stanie się nudna i przewidywalna. Dodatkowo predefiniowane mapy nie rozwiązują nam problemu pojawiania się nowych owoców.

  • Zmienić metodę losujPlansze() w ten sposób, by próbowała wygenerować owoce do tego momentu, aż nie uzyska ich określonej liczby. Należy pamiętać, że na danym polu może być maksymalnie jeden owoc. Po zjedzeniu owocu trzeba uruchamiać tę metodę jeszcze raz, aby dodać na planszy brakujący owoc. W takim przypadku konieczna byłaby jednak modyfikacja metody: liczba powtórzeń pętli musiałaby być potencjalnie duża, a prawdopodobieństwo wygenerowania owocu na danym polu małe, by uniknąć sytuacji, że owoce będą pojawiały się tylko na początku planszy.

  • Wygenerować z góry określoną liczbę owoców w ramach jakiejś dodatkowej struktury danych, takiej jak lista, a następnie losować pola, do których dany owoc przypiszemy, przy założeniu, że w jednym polu może być maksymalnie jeden owoc. W przypadku zjedzenia owocu przez węża, owoc byłby ponownie przypisywany do losowego miejsca na planszy lub byłby on usuwany z listy owoców, a następnie – na jego miejsce na liście – generowany byłby nowy owoc, który znów zostałby przypisany.

Być może sam wymyślisz jeszcze inne sposoby rozwiązania problemu. My proponujemy następujący pomysł:

  • Po zjedzeniu owocu na polu, na którym owoc był, ustawiamy flagę. Następnie próbujemy wygenerować w dowolny sposób (np. korzystając z podanych sposobów) owoc na planszy, jednak nie może on się pojawić na polu, na którym wcześniej została ustawiona wspomniana flaga. Gdy na wszystkich polach (czyli na całej planszy) znajdzie się wspomniana flaga, to wtedy usuwamy ją ze wszystkich pól. W ten sposób uzyskamy taki efekt, że owoce będą się pojawiały – z perspektywy gracza – ciągle w nowych miejscach. W efekcie pola będą się bardzo rzadko powtarzały.

Flagą może być nowy atrybut, który dodamy w ramach klasy Pole.

Zwróć także uwagę na to, że potencjalnych sposobów na efektywne generowanie pola może być naprawdę wiele.

Możemy np. spróbować skorzystać z algorytmu Sita Erastotenesa i generować je tylko na polach, których umowny numer jest liczbą pierwszą albo generować owoc na numerze pola, podzielnym przez liczbę n, gdzie n to liczba punktów węża % 10.

Omówione propozycje algorytmu szukania miejsca na kolejny owoc to tylko przykłady, przedstawiliśmy je, by pokazać, że temat można rozwijać naprawdę kreatywnie.

Przechodzenie węża przez ściany

W tym przypadku istnieje szansa, że musielibyśmy zmodyfikować jeden z warunków zakończenia rozgrywki, zdefiniowany w innym materiale z serii. Algorytm przenoszenia głowy wyglądałby mniej więcej tak dla osi poziomej:

Linia 1. jeżeli waz kropka sprawdzPozycjeX otwórz nawias okrągły zamknij nawias okrągły zamknij nawias ostrokątny plansza kropka rozmiarXPlanszy minus 1 dwukropek. Linia 2. waz kropka ustawPozycje otwórz nawias okrągły 0 przecinek waz kropka sprawdzPozycjeY otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły. Linia 3. w przeciwnym wypadku przecinek jeżeli waz kropka sprawdzPozycjeX otwórz nawias okrągły zamknij nawias okrągły otwórz nawias ostrokątny 0 dwukropek. Linia 4. waz kropka ustawPozycje otwórz nawias okrągły plansza kropka rozmiarXPlanszy minus 1 przecinek waz kropka sprawdzPozycjeY otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły.

Analogicznie dla pionowej:

Linia 1. jeżeli waz kropka sprawdzPozycjeY otwórz nawias okrągły zamknij nawias okrągły zamknij nawias ostrokątny plansza kropka rozmiarYPlanszy minus 1 dwukropek. Linia 2. waz kropka ustawPozycje otwórz nawias okrągły waz kropka sprawdzPozycjeX otwórz nawias okrągły zamknij nawias okrągły przecinek 0 zamknij nawias okrągły. Linia 3. w przeciwnym wypadku przecinek jeżeli waz kropka sprawdzPozycjeY otwórz nawias okrągły zamknij nawias okrągły otwórz nawias ostrokątny 0 dwukropek. Linia 4. waz kropka ustawPozycje otwórz nawias okrągły plansza kropka sprawdzPozycjeX otwórz nawias okrągły zamknij nawias okrągły przecinek plansza kropka rozmiarYPlanszy minus 1 zamknij nawias okrągły.

Należałoby zaimplementować te fragmenty w odpowiednim miejscu, np. przed miejscem, gdzie teraz jest sprawdzane czy wąż znajduje się na planszy, w ramach metody przesun().

Historia gry

Sposobów na zapisanie historii gry jest kilka. Możemy po prostu zapisywać te informacje w specjalnym pliku tekstowym, a następnie – po każdym uruchomieniu programu – wczytywać te informacje i przed rozpoczęciem właściwej rozgrywki wyświetlać wynik.

Można też zapisywać te informacje w specjalnie przygotowanym pliku XML lub wczytywać niewielką bazę danych, na wybranym silniku bazodanowym, obsługującym wybrany język zapytań.

Dla zainteresowanych

Tutaj warto wspomnieć, że w języku Python dostępna jest biblioteka xml.dom, która w prosty sposób pozwala na obsługę plików XML.

Analogiczna biblioteka istnieje w ramach języka Java, javax.xml.

W C++ istnieje kilka bibliotek zapewniających rozwiązanie naszego problemu, takich jak pugixml, TinyXML czy RapidXML.

Jeżeli mowa o bazie danych, to można stworzyć ją specjalnie dla naszego projektu. Jest to jednak temat na osobny materiał.

Przyspieszenie gry i nowe tryby

Samo zwiększenie lub zmniejszenie tempa gry jest rzeczą prostą. W  wątku, który wykorzystuje zamek, wystarczy zwiększyć czas trwania danego wywołania metody sleep(), odpowiednio według potrzeb, tzn. zmniejszyć (w przypadku gdy chcemy grę przyspieszyć) lub zwiększyć (jeżeli chcemy grę spowolnić).

Z dodatkowymi trybami gry sprawa nie jest taka prosta, ponieważ w zależności od pomysłu, tryby te mogłyby wymagać dużych zmian.

Przykładowo: tryb w którym poruszamy się dwoma wężami byłby potencjalnie problematyczny ze względu na sposób wyświetlania węży na mapie. Jednak po drobnych modyfikacjach i to byłoby możliwe.

Stworzenie nowych trybów gry zależy od kreatywności autora programu.

Podsumowanie

Na tym kończymy projekt. Czego się nauczyliśmy?

  • Posługiwać diagramami UML, służącymi do dokumentowania i specyfikowania systemów informatycznych.

  • Korzystać z wielu wątków i je synchronizować.

  • Obsługiwać oprogramowanie do kontroli wersji.

  • Zasad SOLID, wspomagających pisanie czytelnego kodu.

Słownik

API
API

ang. application programming interface jest to zestaw reguł, które określają, w jaki sposób komunikują się ze sobą dwa osobne programy lub elementy systemu; w kontekście OpenGLDirectX w ramach API rozpisany jest zestaw funkcji, dzięki którym można wydawać polecenia procesorowi graficznemu, używając zrozumiałego dla niego języka; gdyby nie interfejsy, to programiści musieliby się skupiać na implementacji osobnych rozwiązań tworzenia grafiki dla każdego systemu i każdego procesora graficznego; API jest więc pewnego rodzaju standardem, który tłumaczy uniwersalny kod na odpowiednie polecenia języków niższego poziomu, np. języka określonego procesora graficznego

biblioteka (programistyczna)
biblioteka (programistyczna)

plik dostarczający definicje podprogramów, typów danych, klasy czy innych elementów; zazwyczaj specjalizuje się w konkretnej dziedzinie

bug
bug

określenie powszechnie stosowane w żargonie informatycznym oznaczające błąd oprogramowania – usterkę, która powoduje nieprawidłowe działanie aplikacji, wynikające z błędu programisty, popełnionego zazwyczaj na etapie tworzenia kodu źródłowego; program służący do diagnozowania tego typu usterek nazywany jest debugerem lub odpluskwiaczem

framework
framework

szkielet budowy aplikacji narzucający jej określoną strukturę i definiujący mechanizmy działania

język zapytań
język zapytań

język służący do tworzenia zapytań w odniesieniu do bazy danych; odpowiedzią na zapytania jest zestawienie danych zwane raportem; najbardziej popularnym językiem zapytań jest SQL

OpenGL
OpenGL

API służące do generowania grafiki dostępne na systemach operacyjnych Windows, Linux i macOS; OpenGL jest standardem otwartym i uniwersalnym, przeznaczonym do generowania grafiki trójwymiarowej; udostępnia około 250 podstawowych funkcji, umożliwiających budowanie nawet bardzo złożonych scen 3D na bazie podstawowych figur geometrycznych.

prymityw graficzny
prymityw graficzny

proste figury geometryczne, z których buduje się inne, złożone obiekty i bardziej skomplikowane struktury

SDL
SDL

ang. simple directmedia layer; biblioteka wysokiego poziomu korzystająca z Direct3D i umożliwiająca odtwarzanie dźwięku, wykrywanie wciśnięć przycisków na myszce lub klawiaturze oraz umożliwiająca wyświetlanie grafiki; jednymi z popularniejszych gier stworzonych w oparciu o tę bibliotekę są Team Fortress 2, Faster Than Light

SFML
SFML

ang. Simple and Fast Multimedia Library; wolne oprogramowanie, napisane w C++; w ramach tej biblioteki dostępne są nie tylko wyświetlanie grafiki, ale również m.in. zarządzanie wątkami, oknami, dźwiękiem, a nawet połączeniem sieciowym; podobnie jak SDL, jest to biblioteka korzystająca z OpenGL

silnik bazodanowy
silnik bazodanowy

oprogramowanie wykorzystywane przez system zarządzania bazą danych do tworzenia, odczytywania, aktualizowania i usuwania danych z bazy danych; większość silników baz danych posiada własne interfejsy aplikacji, pozwalające użytkownikom na podejmowanie interakcji z silnikiem

XML
XML

język znaczników przeznaczony do reprezentowania różnych danych przy zastosowaniu ściśle określonych struktur; jest niezależny od platformy, co ułatwia wymianę dokumentów pomiędzy zróżnicowanymi systemami