
Zapraszam na kolejny projekt zrealizowany w oparciu o Arduino R4 WiFi. Tym razem wykonamy prostą grę "snake" na wyświetlaczu matrycowym znajdującym się na pokładzie Arduino. Gra będzie polegać na sterowaniu tytułowym "wężem", który może "zjadać pokarm" i zwiększać swoją długość. Gra kończy się gdy dojdzie do kolizji węża z samym sobą, co tutaj też obsłużę. Zaczynamy!
Krok 1: przyciski
Zacznijmy od czegoś bardzo przyziemnego. Od przycisków. Potrzebujemy "strzałek", czyli góra, dół, prawo i lewo. Nie przejmujemy się drganiem styków. Starczą zwykłe GPIO w trybie input pullup i cztery przyciski zwierające je do masy gdy je wciśniemy. Oto krótki kod testowy przycisków:
Code: c
Po sprawdzeniu czy wszystko działa, przechodzimy dalej.
Krok 2: Ruch punktu
W tym momencie wprowadziłem już obsługę macierzy LED. Bazowałem na przykładzie Game Of Life z przykładów Arduino R4 WiFi.
Tak jak w Game Of Life, nasza plansza to tablica dwuwymiarowa odpowiadająca poszczególnym LEDom:
Code: c
Dla uproszczenia przyjąłem tutaj, że jeden piksel to jeden bajt, ale tu zasadniczo mamy tylko dwa stany, więc można by to zoptymalizować.
Na początek poruszamy samym punktem. Dla uproszczenia po prostu przyjąłem, że opisują go dwie zmienne globalne, koordynaty X i Y:
Code: c
W pętli odpowiednio nim poruszamy:
Code: c
Linijki z dodawaniem i modulo zapewniają "zapętlenie się" planszy.
Dodatkowo mamy jeszcze wyświetlanie, czyli czyszczenie mapy i nakładanie tego punktu:
Code: c
Całość wykonuję w pętli ze sztucznym opóźnieniem, aby narzucić ilość klatek animacji na sekundę.
Cały kod:
Code: c
Rezultat:
Krok 3: Ruch węża
Niestety jednak sam jeden punkt nam nie wystarczy. Chcemy móc mieć całego węża i to o zmiennej długości. Trzeba zmienić podejście i mechanikę. Postawiłem zatem na tablicę koordynatów punktów:
Code: c
Mamy osobno ustawiony na sztywno limit rozmiaru tablicy (całość pamięci jest od razu alokowana), oraz mamy zmienną przechowującą bieżący rozmiar węża.
Struktura Point reprezentuje jeden punkt węża.
W setup tworzę przykładowego węża, dla testu:
Code: c
Zostaje poruszanie. Trzeba poruszać głowę węża a potem przesuwać kolejne punkty o krok dalej. Myślałem tu, by użyć bufora kołowego, ale uznałem, że łatwiej będzie tak:
Code: c
Osobno obsługuję głowę i osobno przesuwam punkty. Tutaj, w przeciwieństwie do demka z punktem nie pozwalam już na ruchy po skosie. Oprócz tego analogicznie.
Jeszcze wyświetlanie:
Code: c
Rozumiecie ten zapis, prawda? Przechodzę tablicę punktów węża i korzystam z koordynatów x i y do indeksowania tablicy dwuwymiarowej pikseli i tak zapalam odpowiednie piksele.
Całość:
Code: c
Filmik:
Krok 4: Jedzenie dla węża
Teraz trzeba dodać mechanizm pozwalający wydłużać węża. Trzeba mu tworzyć punkciki do jedzenia oraz pozwalać mu je jeść. Zatem najpierw może załóżmy, że na planszy może być tylko jeden punkcik pokarmowy w danym momencie:
Code: c
A potem trzeba w pętli sprawdzać czy głowa węża jest na tym samym pikselu co ten punkt i jeśli tak to wydłużać węża i tworzyć punkcik z jedzeniem na innej, losowej pozycji:
Code: c
To naprawdę tylko tyle! Ważne jest tylko jeszcze tutaj przekopiowanie jednego piksela węża przed wydłużeniem, bo inaczej miałby on nieokreśloną zawartość. Chociaż może starczyłoby "karmić węża" przed wykonaniem ruchu, hmm...
To oczywiście prosta implementacja, można by jeszcze badać czy nowy wylosowany punkt nie znajduje się na wężu, ale tu to pominąłem.
Cały kod:
Code: c
Rezultat:
Krok 5: Kolizja
Została jeszcze jedna, też bardzo ważna mechanika gry. Wąż nie może sam z sobą kolidować. W przeciwnym razie gra by wręcz nie miała sensu. Trzeba zatem sprawdzać, czy taka kolizja występuje.
Po chwili namysłu łatwo dojść do wniosku, że musimy sprawdzać tylko kolizję "łba" z resztą ciała. Nie musimy sprawdzać kolizji pozostałych pikseli między sobą.
Code: c
Wystarczy tylko jedna pętla. Dodałem jeszcze w niej wywołanie funkcji tworzącej efekt "końca gry", który tak naprawdę tego rozpoczyna w kółko miganie ekranem dopóki nie zresetujemy Arduino:
Code: c
Cały kod:
Code: c
Rezultat:
Podsumowanie
To był tylko przykład, ale i tak podstawowa, lecz działająca wersja gry i tak została napisana. Przy ekranie "game over" można by jeszcze wyświetlać ilość zdobytych punktów, chociażby w oparciu o mój wcześniejszy temat o czcionce. Sam kod można by usprawnić, chociażby poprzez zwiększenie rozmiaru tablicy punktów węża i dodanie limitu jego długości (na ten moment zakres tablicy zostanie przekroczony a dalsze działanie programu jest niezdefiniowane - zależy, co będzie w pamięci za tą tablicą). Można by też ulepszyć dodanie nagród itd, ale to pozostawiam czytelnikowi.
Zapraszam do komentowania. Może wkrótce warto zrobić wersję na większym wyświetlaczu, np na układach MAX7219?
Cool? Ranking DIY