Spisu treści:
Wideo: Gra platformowa kontrolowana przez Arduino z joystickiem i odbiornikiem podczerwieni: 3 kroki (ze zdjęciami)
2024 Autor: John Day | [email protected]. Ostatnio zmodyfikowany: 2024-01-30 11:32
Dzisiaj użyjemy mikrokontrolera Arduino do sterowania prostą platformówką opartą na C#. Używam Arduino do pobierania danych z modułu joysticka i wysyłania tych danych do aplikacji C#, która nasłuchuje i dekoduje dane wejściowe przez połączenie szeregowe. Chociaż nie potrzebujesz żadnego wcześniejszego doświadczenia w tworzeniu gier wideo, aby ukończyć projekt, może zająć trochę czasu, aby wchłonąć niektóre rzeczy zachodzące w „pętli gry”, którą omówimy później.
Aby ukończyć ten projekt, będziesz potrzebować:
- Społeczność Visual Studio
- Arduino Uno (lub podobny)
- Moduł kontrolera joysticka
- Cierpliwość
Jeśli jesteś gotowy, aby rozpocząć, kontynuuj!
Krok 1: Podłącz joystick i diodę podczerwieni
Tutaj podłączenie jest dość proste. Dołączyłem schematy pokazujące tylko podłączony joystick, a także konfigurację, której używam, która obejmuje joystick oraz diodę podczerwieni do sterowania grą za pomocą pilota, który jest dostarczany z wieloma zestawami Arduino. Jest to opcjonalne, ale możliwość grania w gry bezprzewodowe wydawała się fajnym pomysłem.
Piny użyte w konfiguracji to:
- A0 (analogowy) <- Oś pozioma lub X
- A1 (analogowy) <- Oś pionowa lub Y
- Pin 2 <- wejście przełącznika joysticka
- Pin 2 <- Wejście LED na podczerwień
- VCC <-5V
- Grunt
- Ziemia #2
Krok 2: Utwórz nowy szkic
Zaczniemy od stworzenia naszego pliku szkicu Arduino. To odpytuje joystick o zmiany i wysyła te zmiany do programu C# co kilka milisekund. W rzeczywistej grze wideo sprawdzalibyśmy port szeregowy w pętli gry pod kątem danych wejściowych, ale zacząłem grę jako eksperyment, więc liczba klatek na sekundę jest w rzeczywistości oparta na liczbie zdarzeń na porcie szeregowym. Właściwie zacząłem projekt w siostrzanym projekcie Arduino, Processing, ale okazuje się, że był znacznie wolniejszy i nie mógł obsłużyć liczby pudełek na ekranie.
Tak więc najpierw utwórz nowy szkic w programie do edycji kodu Arduino. Pokażę mój kod, a następnie wyjaśnię, co robi:
#include "IRremote.h"
// zmienne IR int receiver = 3; // Pin sygnału odbiornika podczerwieni IRrecv irrecv(odbiornik); // utwórz instancję wyników decode_results 'irrecv'; // utwórz instancję 'decode_results' // Zmienne joysticka/gry int xPos = 507; int yPoz = 507; bajt joyXPin = A0; bajt joyYPin = A1; bajt joySwitch = 2; volatile byte clickCounter = -1; int minMoveHigh = 530; int minMoveLow = 490; int currentPrędkość = 550; // Domyślnie = średnia prędkość int speedIncrement = 25; // Kwota do zwiększenia/zmniejszenia prędkości z wejściem Y unsigned long current = 0; // Przechowuje aktualny znacznik czasu int wait = 40; // ms oczekiwania między wiadomościami [Uwaga: niższe czekanie = szybsza liczba klatek na sekundę] volatile bool buttonPressed = false; // Sprawdź, czy przycisk jest wciśnięty void setup() { Serial.begin(9600); pinMode(joySwitch, INPUT_PULLUP); attachInterrupt(0, skok, Opadające); prąd = mili(); // Ustaw aktualny czas // Ustaw odbiornik podczerwieni: irrecv.enableIRIn(); // Uruchom odbiornik } // ustaw void loop() { int xMovement = analogRead(joyXPin); int yPos = analogRead(joyYPin); // Obsługa ruchu Joystick X niezależnie od czasu: if (xMovement > minMoveHigh || xMovement current + wait) { currentSpeed = yPos > minMoveLow && yPos < minMoveHigh // Gdybyś tylko trochę się poruszył… ? currentSpeed // …po prostu zwróć aktualną prędkość: getSpeed(yPos); // Zmieniaj pozycję yPos tylko wtedy, gdy joystick poruszał się znacząco //int distance =; Serial.print((String) xPos + ", " + (String) yPos + ', ' + (String) currentSpeed + '\n'); prąd = mili(); } } // loop int getSpeed(int yPos) { // Wartości ujemne oznaczają przesunięcie joysticka w górę if(yPos 1023 ? 1023: currentSpeed + speedIncrement; } else if(yPos > minMoveHigh) // Interpretacja "Down" { // Ochrona przed przejście poniżej 0 zwróć currentSpeed - speedIncrement < 0 ? 0: currentSpeed - speedIncrement; } } // getSpeed void jump() { buttonPressed = true; // wskaż, że przycisk został naciśnięty } // skok // po naciśnięciu przycisku na remote, obsłuż poprawną odpowiedź void translateIR(decode_results results) // podejmuje działanie na podstawie otrzymanego kodu IR { switch(results.value) { case 0xFF18E7: //Serial.println("2"); currentSpeed += speedIncrement * 2; przerwa; przypadek 0xFF10EF: //Serial.println("4"); xPos = -900; przerwa; przypadek 0xFF38C7: //Serial.println("5"); jump();przerwa; przypadek 0xFF5AA5: //Serial. println("6"); xPos = 900; break; case 0xFF4AB5: //Serial.println("8"); currentSpeed -= speedIncrement * 2; break; default: //Serial.println("inny przycisk"); break; }// Koniec przełącznika } //END translateIR
Starałem się, aby kod był w większości zrozumiały, ale jest kilka rzeczy, o których warto wspomnieć. Jedną rzeczą, którą starałem się wyjaśnić, były następujące wiersze:
int minMoveUp = 520;
int minPrzesuń w dół = 500;
Gdy program jest uruchomiony, wejście analogowe z joysticka ma tendencję do przeskakiwania, zwykle pozostając na poziomie około 507. Aby to naprawić, wejście nie zmienia się, chyba że jest większe niż minYMoveUp lub mniejsze niż minYMoveDown.
pinMode(joySwitch, INPUT_PULLUP);
attachInterrupt(0, skok, Opadające);
Metoda attachInterrupt() pozwala nam przerwać normalną pętlę w dowolnym momencie, dzięki czemu możemy pobierać dane, tak jak naciśnięcie przycisku po kliknięciu przycisku joysticka. Tutaj dołączyliśmy przerwanie w wierszu przed nim, używając metody pinMode(). Ważną uwagą jest to, że aby dołączyć przerwanie do Arduino Uno, musisz użyć pinu 2 lub 3. Inne modele używają różnych pinów przerwań, więc być może będziesz musiał sprawdzić, których pinów używa twój model na stronie Arduino. Drugi parametr dotyczy metody wywołania zwrotnego, zwanej tutaj ISR lub „Procedurą usługi przerwania”. Nie powinien przyjmować żadnych parametrów ani niczego zwracać.
Druk.seryjny(…)
To jest linia, która prześle nasze dane do gry w C#. Tutaj wysyłamy odczyt z osi X, odczyt z osi Y i zmienną prędkości do gry. Te odczyty można rozszerzyć o inne dane wejściowe i odczyty, aby uczynić grę bardziej interesującą, ale tutaj użyjemy tylko kilku.
Jeśli jesteś gotowy, aby przetestować swój kod, prześlij go do Arduino i naciśnij [Shift] + [Ctrl] + [M], aby otworzyć monitor szeregowy i sprawdzić, czy otrzymujesz jakieś dane wyjściowe. Jeśli otrzymujesz dane z Arduino, jesteśmy gotowi przejść do części kodu C#…
Krok 3: Utwórz projekt C#
Aby wyświetlić naszą grafikę, początkowo rozpocząłem projekt w Przetwarzaniu, ale później zdecydowałem, że pokazanie wszystkich obiektów, które musimy wyświetlić, byłoby zbyt wolne. Zdecydowałem się więc na użycie C#, który okazał się znacznie płynniejszy i bardziej responsywny podczas obsługi naszych danych wejściowych.
W przypadku części projektu w języku C# najlepiej jest po prostu pobrać plik.zip i rozpakować go do własnego folderu, a następnie zmodyfikować. W pliku zip znajdują się dwa foldery. Aby otworzyć projekt w programie Visual Studio, wprowadź folder RunnerGame_CSharp w Eksploratorze Windows. W tym miejscu kliknij dwukrotnie plik.sln (rozwiązanie), a program VS załaduje projekt.
W grze stworzyłem kilka różnych klas. Nie będę wchodził w szczegóły dotyczące każdej klasy, ale przedstawię ogólny zarys tego, do czego służą główne zajęcia.
Klasa Pudełkowa
Stworzyłem klasę box, aby umożliwić Ci tworzenie prostych obiektów prostokątnych, które można narysować na ekranie w postaci okna. Pomysł polega na stworzeniu klasy, którą można rozszerzyć o inne klasy, które mogą chcieć rysować jakiś rodzaj grafiki. Słowo kluczowe „virtual” jest używane, aby inne klasy mogły je zastąpić (używając słowa kluczowego „override”). W ten sposób możemy uzyskać to samo zachowanie dla klasy Player i klasy Platform, kiedy zajdzie taka potrzeba, a także modyfikować obiekty w dowolny sposób.
Nie przejmuj się zbytnio wszystkimi właściwościami i rysuj wywołania. Napisałem tę klasę, aby móc ją rozszerzyć o dowolną grę lub program graficzny, który chciałbym stworzyć w przyszłości. Jeśli chcesz po prostu narysować prostokąt w locie, nie musisz pisać tak dużej klasy. Dokumentacja C# zawiera dobre przykłady, jak to zrobić.
Jednak przedstawię trochę logiki mojej klasy „Box”:
public virtual bool IsCollidedX(Box otherObject) { … }
Tutaj sprawdzamy kolizje z obiektami w kierunku X, ponieważ gracz musi sprawdzić kolizje tylko w kierunku Y (góra i dół), jeśli znajduje się w jednej linii z nim na ekranie.
public virtual bool IsCollidedY(Box otherObject) { … }
Kiedy jesteśmy nad lub pod innym obiektem gry, sprawdzamy kolizje Y.
public virtual bool IsCollided(Box otherObject) { … }
Łączy to kolizje X i Y, zwracając, czy jakikolwiek obiekt jest zderzył się z tym.
public virtual void OnPaint(Grafika) { … }
Używając powyższej metody, przekazujemy dowolny obiekt graficzny i używamy go podczas działania programu. Tworzymy dowolne prostokąty, które mogą wymagać narysowania. Można to jednak wykorzystać do różnych animacji. Dla naszych celów prostokąty będą odpowiednie zarówno dla platform, jak i gracza.
Klasa postaci
Klasa Character rozszerza moją klasę Box, więc mamy pewną fizykę po wyjęciu z pudełka. Stworzyłem metodę "CheckForCollisions", aby szybko sprawdzić wszystkie utworzone przez nas platformy pod kątem kolizji. Metoda "Jump" ustawia prędkość w górę odtwarzacza na zmienną JumpSpeed, która jest następnie modyfikowana klatka po klatce w klasie MainWindow.
Tutaj kolizje są obsługiwane nieco inaczej niż w klasie Box. Zdecydowałem w tej grze, że skacząc w górę, możemy przeskoczyć przez platformę, ale złapie ona naszego gracza schodząc w dół, jeśli się z nią zderzymy.
Klasa platformy
W tej grze używam tylko konstruktora tej klasy, który pobiera współrzędną X jako dane wejściowe, obliczając wszystkie lokalizacje X platform w klasie MainWindow. Każda platforma jest ustawiona na losowej współrzędnej Y od 1/2 ekranu do 3/4 wysokości ekranu. Wysokość, szerokość i kolor są również generowane losowo.
Klasa MainWindow
To tutaj umieszczamy całą logikę, która ma być używana podczas działania gry. Najpierw w konstruktorze wypisujemy wszystkie dostępne dla programu porty COM.
foreach(string port w SerialPort. GetPortNames())
Console. WriteLine("DOSTĘPNE PORTY: " + port);
Wybieramy, na którym będziemy akceptować komunikację, w zależności od portu, z którego korzysta już Twoje Arduino:
SerialPort = new SerialPort(SerialPort. GetPortNames()[2], 9600, Parity. None, 8, StopBits. One);
Zwróć szczególną uwagę na polecenie: SerialPort. GetPortNames()[2]. [2] oznacza, którego portu szeregowego użyć. Na przykład, jeśli program wypisze "COM1, COM2, COM3", będziemy nasłuchiwać na COM3, ponieważ numeracja zaczyna się od 0 w tablicy.
Również w konstruktorze tworzymy wszystkie platformy z półlosowymi odstępami i rozmieszczeniem w kierunku Y na ekranie. Wszystkie platformy są dodawane do obiektu List, który w C# jest po prostu bardzo przyjaznym dla użytkownika i wydajnym sposobem zarządzania strukturą danych podobną do tablicy. Następnie tworzymy Player, który jest naszym obiektem Character, ustawiamy wynik na 0 i ustawiamy GameOver na false.
private static void DataReceived(object sender, SerialDataReceivedEventArgs e)
Jest to metoda wywoływana, gdy dane są odbierane przez port szeregowy. To tutaj stosujemy całą naszą fizykę, decydujemy, czy wyświetlić grę, przesunąć platformy itp. Jeśli kiedykolwiek zbudowałeś grę, zazwyczaj masz coś, co nazywa się „pętlą gry”, która jest wywoływana za każdym razem, gdy klatka odświeża. W tej grze metoda DataReceived działa jak pętla gry, manipulując fizyką tylko podczas odbierania danych z kontrolera. Być może lepiej byłoby ustawić Timer w głównym oknie i odświeżyć obiekty na podstawie otrzymanych danych, ale ponieważ jest to projekt Arduino, chciałem stworzyć grę, która faktycznie działała na podstawie danych z niego pochodzących.
Podsumowując, ta konfiguracja daje dobrą podstawę do rozszerzenia gry na coś użytecznego. Chociaż fizyka nie jest idealna, działa wystarczająco dobrze dla naszych celów, czyli używania Arduino do czegoś, co każdy lubi: grania w gry!
Zalecana:
Kontrolowana przez Wi-Fi matryca LED Strip Wyświetlacz Podświetlenie zegara: 3 kroki (ze zdjęciami)
Kontrolowane przez Wi-Fi paski LED Matrix Wyświetlacz Oświetlenie zegara: Programowalne paski LED, np. oparte na WS2812, są fascynujące. Zastosowania są różnorodne i szybko można uzyskać imponujące rezultaty. I jakoś budowanie zegarów wydaje mi się kolejną dziedziną, o której dużo myślę. Zaczynając od pewnego doświadczenia w
Kontrolowana przez Internet maszyna do baniek mydlanych: 4 kroki (ze zdjęciami)
Kontrolowana przez Internet maszyna do baniek: Każdy wie, że puszczanie baniek to świetna zabawa, ale może to być ciężka praca. Możemy rozwiązać ten problem, po prostu budując sterowaną przez Internet maszynę do baniek, delegując wysiłek, jednocześnie zbierając wszystkie nagrody. Dla pacjentów hospitalizowanych możesz sprawdzić
Dioda LED kontrolowana przez serwer HTTP - Ameba Arduino: 3 kroki
Dioda LED sterowana przez serwer HTTP - Ameba Arduino: Sterowanie diodą LED jest łatwe za pomocą dowolnego wybranego mikrokontrolera, ale bezprzewodowe sterowanie diodą LED w przeglądarce telefonu komórkowego jest naprawdę fajne i przyjemne. Właściwie jest to już projekt IoT, ponieważ możesz używać tego samego serwera do kontrolowania rzeczy
Wytwornica mgły Ultimate Dry Ice - Kontrolowana przez Bluetooth, zasilana bateryjnie i drukowana w 3D.: 22 kroki (ze zdjęciami)
Wytwornica mgły do suchego lodu - sterowana przez Bluetooth, zasilana bateryjnie i drukowana w 3D.: Niedawno potrzebowałem maszyny do wytwarzania suchego lodu, aby uzyskać efekty teatralne na lokalny pokaz. Nasz budżet nie wystarczyłby na zatrudnienie profesjonalnego, więc zamiast tego zbudowałem to. Jest w większości drukowany w 3D, sterowany zdalnie przez Bluetooth, zasilany bateryjnie
Kontrolowana przez Arduino stacja dokująca do telefonu z lampami: 14 kroków (ze zdjęciami)
Kontrolowana przez Arduino stacja dokująca do telefonu z lampami: pomysł był dość prosty; stworzyć stację dokującą do ładowania telefonu, która włączy lampę tylko podczas ładowania telefonu. Jednak, jak to często bywa, rzeczy, które początkowo wydają się proste, mogą stać się nieco bardziej skomplikowane w ich wykonaniu. To jest t