Tartalomjegyzék:

Arduino által vezérelt platformozó játék joystick-mal és IR-vevővel: 3 lépés (képekkel)
Arduino által vezérelt platformozó játék joystick-mal és IR-vevővel: 3 lépés (képekkel)

Videó: Arduino által vezérelt platformozó játék joystick-mal és IR-vevővel: 3 lépés (képekkel)

Videó: Arduino által vezérelt platformozó játék joystick-mal és IR-vevővel: 3 lépés (képekkel)
Videó: Leap Motion SDK 2024, November
Anonim
Arduino által vezérelt platformozó játék joystick-szal és IR-vevővel
Arduino által vezérelt platformozó játék joystick-szal és IR-vevővel

Ma egy Arduino mikrokontrollert fogunk használni egy egyszerű C#alapú platformjáték vezérléséhez. Az Arduino -t használom a joystick modulból történő bevitelhez, és elküldöm a bemenetet a C# alkalmazásnak, amely soros kapcsolaton keresztül figyeli és dekódolja a bemenetet. Bár a projekt befejezéséhez nincs szükség korábbi tapasztalatokra a videojátékok készítésében, előfordulhat, hogy némi időbe telik, amíg felveszi a „játékkörben” zajló dolgokat, amelyeket később tárgyalunk.

A projekt befejezéséhez szüksége lesz:

  • Visual Studio közösség
  • Egy Arduino Uno (vagy hasonló)
  • Joystick vezérlő modul
  • Türelem

Ha készen áll a kezdésre, folytassa!

Lépés: Csatlakoztassa a botkormányt és az IR LED -et

Csatlakoztassa a joystickot és az IR LED -et
Csatlakoztassa a joystickot és az IR LED -et
Csatlakoztassa a joystickot és az IR LED -et
Csatlakoztassa a joystickot és az IR LED -et

Itt a csatlakoztatás meglehetősen egyszerű. Mellékeltem azokat a diagramokat, amelyek csak a joystickot csatlakoztatják, valamint az általam használt beállítást, amely magában foglalja a joystickot és egy infravörös LED -et a játék távirányítóval történő vezérléséhez, amely sok Arduino készlettel jár. Ez opcionális, de jó ötletnek tűnt, hogy vezeték nélküli játékokat végezhessünk.

A beállításban használt csapok:

  • A0 (analóg) <- Vízszintes vagy X tengely
  • A1 (analóg) <- Függőleges vagy Y tengely
  • 2. tű <- Joystick Switch bemenet
  • 2. tű <- Infravörös LED bemenet
  • VCC <- 5V
  • Talaj
  • 2. talaj

2. lépés: Hozzon létre egy új vázlatot

Hozzon létre egy új vázlatot
Hozzon létre egy új vázlatot

Kezdjük az Arduino vázlatfájl létrehozásával. Ez lekérdezi a joystickot a változásokról, és néhány milliszekundumban elküldi ezeket a módosításokat a C# programnak. Egy tényleges videojátékban ellenőriznénk a soros portot egy játékhurokban, hogy bemenet legyen -e, de a játékot kísérletként kezdtem, tehát a képkocka sebessége valójában a soros porton lévő események számán alapul. Valójában az Arduino testvérprojektben, a Processingben kezdtem el a projektet, de kiderült, hogy sokkal -sokkal lassabb volt, és nem tudtam kezelni a képernyőn látható dobozok számát.

Tehát először hozzon létre egy új vázlatot az Arduino kódszerkesztő programban. Megmutatom a kódomat, majd elmagyarázom, mit csinál:

#include "IRremote.h"

// IR változók int vevő = 3; // Infravörös vevő jelcsatlakozója IRrecv irrecv (vevő); // hozza létre az "irrecv" decode_results eredmények példányát; // "decode_results" példány létrehozása // Joystick/game variables int xPos = 507; int yPos = 507; bájt joyXPin = A0; byte joyYPin = A1; bájt joySwitch = 2; illékony bájt clickCounter = -1; int minMoveHigh = 530; int minMoveLow = 490; int currentSpeed = 550; // Alapértelmezett = átlagos sebesség int speedIncrement = 25; // A sebesség növelésének/csökkentésének összege Y bemenet aláírás nélküli hosszú áram = 0; // Tartja az aktuális időbélyeget int wait = 40; // ms várni az üzenetek között [Megjegyzés: alacsonyabb várakozás = gyorsabb framerate] illékony bool gomb Pressed = false; // Mérő, ha a gombot megnyomják void setup () {Serial.begin (9600); pinMode (joySwitch, INPUT_PULLUP); attachInterrupt (0, ugrás, esés); áram = millis (); // Az aktuális idő beállítása // Infravörös vevő beállítása: irrecv.enableIRIn (); // Indítsa el a vevőt} // setup void loop () {int xMovement = analogRead (joyXPin); int yPos = analógRead (joyYPin); // Kezelje a Joystick X mozgást az időzítéstől függetlenül: if (xMovement> minMoveHigh || xMovement current + wait) {currentSpeed = yPos> minMoveLow && yPos <minMoveHigh // Ha csak egy kicsit is mozogna…? currentSpeed //… csak adja vissza az aktuális sebességet: getSpeed (yPos); // Csak akkor változtassa meg az yPos -t, ha a joystick jelentősen elmozdult // int distance =; Serial.print ((String) xPos + "," + (String) yPos + ',' + (String) currentSpeed + '\ n'); áram = millis (); }} // hurok int getSpeed (int yPos) {// A negatív értékek azt jelzik, hogy a joystick felfelé mozdult, ha (yPos 1023? 1023: currentSpeed + speedIncrement;} else if (yPos> minMoveHigh) // "Le" értelmezve {// Védelem 0 alá megy visszatérési áramSpeed - speedIncrement <0? 0: currentSpeed - speedIncrement;}} // getSpeed void jump () {buttonPressed = true; // A gomb megnyomásának jelzése.} // ugrás // Amikor egy gombot megnyomnak a távoli, kezelje a megfelelő választ void translateIR (decode_results results) // a kapott IR -kód alapján cselekszik {switch (results.value) {case 0xFF18E7: //Serial.println("2 "); currentSpeed += speedIncrement * 2; break; case 0xFF10EF: //Serial.println("4 "); xPos = -900; break; case 0xFF38C7: //Serial.println("5"); jump (); break; case 0xFF5AA5: // Serial. println ("6"); xPos = 900; break; case 0xFF4AB5: //Serial.println("8 "); currentSpeed -= speedIncrement * 2; break; default: //Serial.println (" other button "); break;} // End switch} // END translateIR

Próbáltam úgy létrehozni a kódot, hogy többnyire magától értetődő legyen, de van néhány dolog, amit érdemes megemlíteni. Egy dologgal próbáltam elszámolni a következő sorokban:

int minYMoveUp = 520;

int minYMoveDown = 500;

Amikor a program fut, a joystick analóg bemenete hajlamos körbeugrani, általában 507 körül marad. Ennek korrigálására a bemenet nem változik, ha nem nagyobb, mint minYMoveUp, vagy kisebb, mint minYMoveDown.

pinMode (joySwitch, INPUT_PULLUP);

attachInterrupt (0, ugrás, esés);

Az attachInterrupt () metódus lehetővé teszi, hogy bármikor megszakítsuk a normál ciklust, hogy be tudjunk írni, mint például a gomb megnyomása, amikor a joystick gombra kattintanak. Itt a pinMode () metódussal csatoltuk a megszakítást az előtte lévő sorhoz. Itt fontos megjegyzés, hogy az Arduino Uno megszakításának csatolásához vagy a 2 -es vagy a 3 -as tűt kell használnia. Más modellek különböző megszakítócsapokat használnak, ezért előfordulhat, hogy ellenőriznie kell, hogy a modell mely csapokat használja az Arduino webhelyen. A második paraméter a visszahívási módszerre vonatkozik, itt ISR -nek vagy "Interrupt Service Rutin" -nak nevezzük. Nem szabad paramétereket venni vagy semmit visszaadni.

Serial.print (…)

Ez az a sor, amely elküldi adatainkat a C# játékhoz. Itt az X-tengely leolvasását, az Y-tengely leolvasását és egy sebességváltozót küldünk a játéknak. Ezek az értékek további bemenetekre és olvasmányokra is kiterjeszthetők, hogy a játék érdekesebb legyen, de itt csak párat fogunk használni.

Ha készen áll a kód tesztelésére, töltse fel az Arduino -ba, és nyomja meg a [Shift] + [Ctrl] + [M] gombot a soros monitor megnyitásához, és nézze meg, hogy kap -e kimenetet. Ha adatokat kap az Arduino -tól, készen állunk a kód C# szakaszára lépni…

3. lépés: Hozza létre a C# projektet

A grafikáink megjelenítéséhez kezdetben elindítottam egy projektet a Processingben, de később úgy döntöttem, hogy túl lassú lesz megjeleníteni az összes megjelenítendő objektumot. Így a C#használatát választottam, amely sokkal simábbnak és érzékenyebbnek bizonyult a bevitt adatok kezelésekor.

A projekt C# részéhez a legjobb, ha egyszerűen letölti a.zip fájlt, és kibontja azt a saját mappájába, majd módosítja. A zip fájlban két mappa található. A projekt Visual Studio -ban történő megnyitásához adja meg a RunnerGame_CSharp mappát a Windows Intézőben. Itt kattintson duplán a.sln (megoldás) fájlra, és a VS betölti a projektet.

Van néhány különböző osztály, amelyet a játékhoz készítettem. Nem részletezem az egyes osztályok minden részletét, de áttekintést adok arról, hogy mire szolgálnak a fő órák.

A Box osztály

Azért hoztam létre a dobozosztályt, hogy lehetővé tegye egyszerű téglalap alakú objektumok létrehozását, amelyek Windows képernyőn rajzolhatók. Az ötlet az, hogy hozzon létre egy osztályt, amely kibővíthető más osztályokkal, amelyek esetleg grafikákat szeretnének rajzolni. A "virtuális" kulcsszót arra használják, hogy más osztályok felülírhassák őket (a "felülbírálás" kulcsszó használatával). Így szükség esetén ugyanazt a viselkedést kaphatjuk a Player és a Platform osztályok esetében is, és szükség szerint módosíthatjuk az objektumokat is.

Ne aggódjon túl sokat az összes ingatlan miatt, és hívásokat kezdeményezzen. Azért írtam ezt az osztályt, hogy kibővíthessem azt a játékot vagy grafikai programot, amelyet a jövőben szeretnék elkészíteni. Ha menet közben egyszerűen meg kell rajzolnia egy téglalapot, nem kell kiírnia egy ilyen nagy osztályt. A C# dokumentáció jó példákat tartalmaz erre.

Azonban leírom a "Box" osztály néhány logikáját:

nyilvános virtuális bool IsCollidedX (Box otherObject) {…}

Itt ellenőrizzük az ütközéseket az X irányú tárgyakkal, mert a játékosnak csak akkor kell ellenőriznie az Y irányú ütközéseket (fel és le), ha vele áll a képernyőn.

nyilvános virtuális bool IsCollidedY (Box otherObject) {…}

Amikor túl vagyunk egy másik játékobjektumon vagy alatta, ellenőrizzük az Y ütközéseket.

nyilvános virtuális bool IsCollided (Box otherObject) {…}

Ez egyesíti az X és Y ütközéseket, és visszaadja, hogy bármilyen tárgy ütközik -e ezzel.

nyilvános virtuális void OnPaint (grafikus grafika) {…}

A fenti módszerrel bármely grafikus objektumot átadunk, és a program futása közben használjuk. Létrehozunk minden téglalapot, amelyet esetleg ki kell rajzolni. Ez azonban sokféle animációhoz használható. Céljaink szerint a téglalapok mind a platformok, mind a lejátszó számára jól fognak működni.

A karakterosztály

A Karakter osztály kiterjeszti a Box osztályomat, így bizonyos fizikákat nem kapunk. Azért hoztam létre a "CheckForCollisions" módszert, hogy gyorsan ellenőrizhessük az összes általunk létrehozott platformot ütközés szempontjából. Az "Ugrás" módszer a játékos felfelé irányuló sebességét a JumpSpeed változóra állítja, amelyet ezután képkockánként módosítanak a MainWindow osztályban.

Az ütközéseket itt kissé eltérően kezelik, mint a Box osztályban. Ebben a játékban úgy döntöttem, hogy ha felfelé ugrunk, átugorhatunk egy platformot, de lefelé menet elkapja a játékosunkat, ha ütközik vele.

A platformosztály

Ebben a játékban csak az osztály konstruktorát használom, amely X-koordinátát vesz bemenetként, és kiszámítja a platformok összes X helyét a MainWindow osztályban. Minden platform véletlenszerű Y-koordinátán van beállítva a képernyő 1/2 és a képernyő magasságának 3/4 része között. A magasság, a szélesség és a szín is véletlenszerűen generálódik.

A MainWindow osztály

Ez az a pont, ahol minden logikát felhasználunk a játék futása közben. Először a konstruktorban kinyomtatjuk a program számára elérhető összes COM portot.

foreach (karakterlánc -port a SerialPort. GetPortNames () -ban)

Console. WriteLine ("AVAILABLE PORTS:" + port);

Kiválasztjuk, hogy melyiken fogadjuk el a kommunikációt, aszerint, hogy az Arduino melyik portját használja:

SerialPort = új SerialPort (SerialPort. GetPortNames () [2], 9600, Parity. None, 8, StopBits. One);

Ügyeljen a SerialPort. GetPortNames () [2] parancsra. A [2] jelzi, hogy melyik soros portot kell használni. Például, ha a program kinyomtatja a "COM1, COM2, COM3" -ot, akkor a COM3 -on hallgatnánk, mert a számozás 0 -val kezdődik a tömbben.

Szintén a konstruktorban hozunk létre minden platformot félig véletlenszerű térközökkel és Y képernyős elhelyezéssel a képernyőn. Minden platform hozzáadódik egy List objektumhoz, ami a C# -ban egyszerűen nagyon felhasználóbarát és hatékony módja a tömbszerű adatstruktúra kezelésének. Ezután létrehozzuk a Játékost, amely a Karakter objektumunk, a pontszámot 0 -ra állítjuk, a GameOver értékét pedig hamis értékre állítjuk.

private static void DataReceived (objektumküldő, SerialDataReceivedEventArgs e)

Ezt a módszert hívják meg, amikor adatokat fogad a soros porton. Itt alkalmazzuk minden fizikánkat, és eldöntjük, hogy megjelenítjük -e a játékot, áthelyezzük -e a platformokat stb. felfrissíti. Ebben a játékban a DataReceived módszer játékhurokként működik, csak a fizikát manipulálja, mivel a vezérlőtől származó adatok érkeznek. Lehet, hogy jobban működött volna, ha beállított egy időzítőt a főablakban, és frissítette az objektumokat a kapott adatok alapján, de mivel ez egy Arduino -projekt, szerettem volna egy olyan játékot készíteni, amely valóban futott a beérkező adatok alapján..

Összefoglalva, ez a beállítás jó alapot ad ahhoz, hogy a játékot valami használhatóvá bővítsük. Bár a fizika nem egészen tökéletes, de elég jól működik a mi céljainkhoz, vagyis az Arduino használatára, ami mindenkinek tetszik: játék!

Ajánlott: