Inhoudsopgave:
Video: Arduino-gestuurd platformspel met joystick en IR-ontvanger - Ajarnpa
2024 Auteur: John Day | [email protected]. Laatst gewijzigd: 2024-01-30 11:19
Vandaag gaan we een Arduino-microcontroller gebruiken om een eenvoudig op C# gebaseerd platformspel te besturen. Ik gebruik de Arduino om invoer van een joystickmodule te krijgen en die invoer naar de C # -toepassing te sturen die de invoer via een seriële verbinding luistert en decodeert. Hoewel je geen eerdere ervaring met het bouwen van videogames nodig hebt om het project te voltooien, kan het enige tijd duren voordat je een aantal van de dingen die in de "game-loop" gebeuren, die we later zullen bespreken, op je in laten werken.
Om dit project te voltooien, hebt u nodig:
- Visual Studio-gemeenschap
- Een Arduino Uno (of vergelijkbaar)
- Een joystick-controllermodule
- Geduld
Als je klaar bent om te beginnen, ga dan door!
Stap 1: Sluit de joystick en IR-LED aan
Hier is de aansluiting vrij eenvoudig. Ik heb diagrammen toegevoegd die alleen de aangesloten joystick tonen, evenals de setup die ik gebruik, waaronder de joystick plus een infrarood-LED voor het besturen van het spel met een afstandsbediening, die bij veel Arduino-kits wordt geleverd. Dit is optioneel, maar het leek me een gaaf idee om draadloos te kunnen gamen.
De pinnen die in de opstelling worden gebruikt zijn:
- A0 (analoog) <- Horizontaal of X-as
- A1 (analoog) <- Verticaal of Y-as
- Pin 2 <- Joystick Switch-ingang
- Pin 2 <- Infrarood LED-ingang
- VCC <- 5V
- Grond
- Grond #2
Stap 2: Maak een nieuwe schets
We beginnen met het maken van ons Arduino-schetsbestand. Dit peilt de joystick naar wijzigingen en stuurt die wijzigingen om de paar milliseconden naar het C#-programma. In een echte videogame controleerden we de seriële poort in een gameloop op invoer, maar ik begon de game als een experiment, dus de framerate is eigenlijk gebaseerd op het aantal gebeurtenissen op de seriële poort. Ik was eigenlijk aan het project begonnen in het Arduino-zusterproject Processing, maar het bleek veel, veel langzamer te zijn en het aantal vakjes op het scherm niet aan te kunnen.
Maak dus eerst een nieuwe Sketch in het Arduino-code-editorprogramma. Ik zal mijn code laten zien en dan uitleggen wat het doet:
#include "IRremote.h"
// IR-variabelen int ontvanger = 3; // Signaalpen van IR-ontvanger IRrecv irrecv (ontvanger); // maak instantie van 'irrecv' decode_results resultaten; // maak een instantie van 'decode_results' // Joystick/game-variabelen int xPos = 507; int yPos = 507; byte joyXPin = A0; byte joyYPin = A1; byte joySwitch = 2; vluchtige byte clickCounter = -1; int minMoveHigh = 530; int minMoveLow = 490; int stroomsnelheid = 550; // Standaard = een gemiddelde snelheid int speedIncrement = 25; // Bedrag om de snelheid te verhogen/verlagen met Y-invoer zonder teken, lange stroom = 0; // Houdt huidige tijdstempel int wait = 40; // ms om te wachten tussen berichten [Opmerking: lagere wachttijd = snellere framerate] vluchtige bool buttonPressed = false; // Meet of de knop wordt ingedrukt void setup () { Serial.begin (9600); pinMode (joySwitch, INPUT_PULLUP); attachInterrupt(0, springen, VALLEN); stroom = millis(); // Stel de huidige tijd in // Stel infraroodontvanger in: irrecv.enableIRIn(); // Start de ontvanger} // setup void loop () {int xMovement = analogRead (joyXPin); int yPos = analogRead(joyYPin); // Hanteer de Joystick X-beweging ongeacht de timing: if (xMovement > minMoveHigh || xMovement current + wait) { currentSpeed = yPos > minMoveLow && yPos < minMoveHigh // Als het maar een klein beetje bewogen wordt… ? currentSpeed // …geef gewoon de huidige snelheid terug: getSpeed(yPos); // Wijzig yPos alleen als de joystick aanzienlijk is bewogen //int distance =; Serial.print((String) xPos + ", " + (String) yPos + ', ' + (String) currentSpeed + '\n'); stroom = millis(); } } // loop int getSpeed (int yPos) { // Negatieve waarden geven aan dat Joystick omhoog is bewogen if (yPos 1023 ? 1023: currentSpeed + speedIncrement; } else if (yPos > minMoveHigh) // Interpreted "Down" { // Protect from onder 0 terugkeren currentSpeed - speedIncrement < 0 ? 0: currentSpeed - speedIncrement; } } // getSpeed void jump() { buttonPressed = true; // Geeft aan dat de knop is ingedrukt. } // jump // Wanneer een knop wordt ingedrukt op de remote, handel de juiste reactie af void translateIR (decode_results results) // onderneemt actie op basis van ontvangen IR-code {switch(results.valu) { 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(" andere knop "); pauze; }// Eindschakelaar } //END translateIR
Ik heb geprobeerd de code zo duidelijk mogelijk te maken, maar er zijn een paar dingen die het vermelden waard zijn. Een ding dat ik probeerde te verklaren was in de volgende regels:
int minYMoveUp = 520;
int minYMoveDown = 500;
Wanneer het programma draait, heeft de analoge invoer van de joystick de neiging om rond te springen, meestal rond de 507. Om dit te corrigeren, verandert de invoer niet tenzij deze groter is dan minYMoveUp, of kleiner dan minYMoveDown.
pinMode (joySwitch, INPUT_PULLUP);
attachInterrupt(0, spring, FALLING);
Met de methode attachInterrupt() kunnen we de normale lus op elk moment onderbreken, zodat we invoer kunnen nemen, zoals de knop die wordt ingedrukt wanneer op de joystickknop wordt geklikt. Hier hebben we de interrupt in de regel ervoor toegevoegd, met behulp van de methode pinMode(). Een belangrijke opmerking hierbij is dat om een interrupt op de Arduino Uno te bevestigen, je ofwel pin 2 of 3 moet gebruiken. Andere modellen gebruiken andere interrupt-pinnen, dus het kan zijn dat je op de Arduino-website moet controleren welke pinnen je model gebruikt. De tweede parameter is voor de callback-methode, hier een ISR of een "Interrupt Service Routine" genoemd. Het mag geen parameters gebruiken of iets retourneren.
Serie.afdruk(…)
Dit is de regel die onze gegevens naar de C#-game stuurt. Hier sturen we de X-as-aflezing, de Y-as-aflezing en een snelheidsvariabele naar het spel. Deze metingen kunnen worden uitgebreid met andere invoer en metingen om het spel interessanter te maken, maar hier zullen we er slechts een paar gebruiken.
Als je klaar bent om je code te testen, upload deze dan naar de Arduino en druk op [Shift] + [Ctrl] + [M] om de seriële monitor te openen en te kijken of je output krijgt. Als u gegevens van de Arduino ontvangt, zijn we klaar om verder te gaan naar het C # -gedeelte van de code …
Stap 3: Maak het C#-project
Om onze afbeeldingen weer te geven, begon ik aanvankelijk een project in Processing, maar later besloot ik dat het te traag zou zijn om alle objecten weer te geven die we moeten weergeven. Dus koos ik ervoor om C# te gebruiken, dat veel soepeler en responsiever bleek te zijn bij het verwerken van onze invoer.
Voor het C#-gedeelte van het project is het het beste om gewoon het.zip-bestand te downloaden en het uit te pakken in zijn eigen map, en het vervolgens aan te passen. Er zijn twee mappen in het zip-bestand. Om het project in Visual Studio te openen, voert u de map RunnerGame_CSharp in Windows Verkenner in. Dubbelklik hier op het.sln-bestand (oplossing) en VS zal het project laden.
Er zijn een paar verschillende klassen die ik voor het spel heb gemaakt. Ik zal niet ingaan op alle details over elke klasse, maar ik zal een overzicht geven van waar de hoofdklassen voor zijn.
The Box Class
Ik heb de box-klasse gemaakt waarmee je eenvoudige rechthoekige objecten kunt maken die op het scherm in een venstervorm kunnen worden getekend. Het idee is om een klasse te maken die kan worden uitgebreid met andere klassen die misschien een soort van afbeeldingen willen tekenen. Het "virtuele" sleutelwoord wordt gebruikt zodat andere klassen deze kunnen overschrijven (met behulp van het "override" sleutelwoord). Op die manier kunnen we hetzelfde gedrag krijgen voor de klasse Player en de klasse Platform wanneer dat nodig is, en ook de objecten naar wens aanpassen.
Maak je niet al te veel zorgen over alle eigendommen en trek telefoontjes aan. Ik heb deze les geschreven zodat ik deze kon uitbreiden voor elk spel of grafisch programma dat ik in de toekomst zou willen maken. Als je eenvoudig een rechthoek moet tekenen, hoef je zo'n grote klasse niet uit te schrijven. De C#-documentatie heeft goede voorbeelden van hoe u dit kunt doen.
Ik zal echter een deel van de logica van mijn "Box" -klasse uiteenzetten:
openbare virtuele bool IsCollidedX(Box otherObject) { … }
Hier controleren we op botsingen met objecten in de X-richting, omdat de speler alleen hoeft te controleren op botsingen in de Y-richting (omhoog en omlaag) als hij ermee in lijn staat op het scherm.
openbare virtuele bool IsCollidedY(Box otherObject) { … }
Wanneer we ons boven of onder een ander spelobject bevinden, controleren we op Y-botsingen.
openbare virtuele bool IsCollided(Box otherObject) { … }
Dit combineert X- en Y-botsingen en geeft terug of een object hiermee is gebotst.
openbare virtuele leegte OnPaint (grafische afbeeldingen) { … }
Met behulp van de bovenstaande methode geven we elk grafisch object door en gebruiken het terwijl het programma draait. We maken alle rechthoeken die mogelijk moeten worden getekend. Dit kan echter voor verschillende animaties worden gebruikt. Voor onze doeleinden zullen rechthoeken het goed doen voor zowel de platforms als de speler.
De karakterklasse
De Character-klasse is een uitbreiding van mijn Box-klasse, dus we hebben bepaalde fysica uit de doos. Ik heb de "CheckForCollisions"-methode gemaakt om snel alle platforms die we hebben gemaakt te controleren op een botsing. De "Jump"-methode stelt de opwaartse snelheid van de speler in op de JumpSpeed-variabele, die vervolgens frame voor frame wordt gewijzigd in de klasse MainWindow.
Aanrijdingen worden hier iets anders afgehandeld dan in de Box-klasse. Ik heb in dit spel besloten dat als we omhoog springen, we door een platform kunnen springen, maar het zal onze speler op de weg naar beneden vangen als hij ermee in botsing komt.
De platformklas
In dit spel gebruik ik alleen de constructor van deze klasse die een X-coördinaat als invoer neemt en alle X-locaties van het platform in de MainWindow-klasse berekent. Elk platform is opgesteld op een willekeurige Y-coördinaat van 1/2 het scherm tot 3/4 van de hoogte van het scherm. De hoogte, breedte en kleur worden ook willekeurig gegenereerd.
De MainWindow-klasse
Hier plaatsen we alle logica die moet worden gebruikt terwijl het spel draait. Eerst drukken we in de constructor alle COM-poorten af die beschikbaar zijn voor het programma.
foreach (stringpoort in SerialPort. GetPortNames())
Console. WriteLine("BESCHIKBARE POORTEN: " + poort);
We kiezen op welke we communicatie accepteren, afhankelijk van welke poort je Arduino al gebruikt:
SerialPort = nieuwe SerialPort(SerialPort. GetPortNames()[2], 9600, Parity. None, 8, StopBits. One);
Let goed op het commando: SerialPort. GetPortNames()[2]. De [2] geeft aan welke seriële poort moet worden gebruikt. Als het programma bijvoorbeeld "COM1, COM2, COM3" zou afdrukken, zouden we naar COM3 luisteren omdat de nummering begint bij 0 in de array.
Ook in de constructor maken we alle platforms met semi-willekeurige tussenruimte en plaatsing in de Y-richting op het scherm. Alle platforms worden toegevoegd aan een List-object, wat in C# gewoon een zeer gebruiksvriendelijke en efficiënte manier is om een array-achtige datastructuur te beheren. Vervolgens maken we de speler, ons Character-object, stellen de score in op 0 en stellen GameOver in op false.
private statische leegte DataReceived (objectafzender, SerialDataReceivedEventArgs e)
Dit is de methode die wordt aangeroepen wanneer gegevens worden ontvangen op de seriële poort. Dit is waar we al onze fysica toepassen, beslissen of we game over willen weergeven, de platforms willen verplaatsen, enz. Als je ooit een game hebt gebouwd, heb je over het algemeen een zogenaamde "gameloop", die elke keer dat het frame wordt genoemd verfrist. In dit spel fungeert de DataReceived-methode als de spellus, waarbij alleen de fysica wordt gemanipuleerd wanneer gegevens van de controller worden ontvangen. Het had misschien beter gewerkt om een timer in het hoofdvenster in te stellen en de objecten te vernieuwen op basis van de ontvangen gegevens, maar aangezien dit een Arduino-project is, wilde ik een spel maken dat daadwerkelijk draaide op basis van de gegevens die eruit kwamen.
Kortom, deze opzet geeft een goede basis om het spel uit te breiden tot iets bruikbaars. Hoewel de fysica niet helemaal perfect is, werkt het goed genoeg voor onze doeleinden, namelijk om de Arduino te gebruiken voor iets dat iedereen leuk vindt: spelletjes spelen!
Aanbevolen:
Hoe de BLDC-motor te besturen met Arduino en joystick: 6 stappen
Hoe BLDC-motor te besturen met Arduino en joystick: Hallo vrienden in deze tutorial laat ik je zien hoe je een borstelloze gelijkstroommotor, ook bekend als BLDC-motor, bestuurt met Arduino en joystick
Tiny USB-joystick: 5 stappen (met afbeeldingen)
Tiny USB-joystick: deze instructies laten zien hoe je een heel eenvoudige kleine USB-joystick kunt maken. Deze instructable is gerelateerd aan Hall Effect USB-joystick voor het bieden van een goedkope oplossing
USB-conversie met joystick uit de jaren 80: 7 stappen (met afbeeldingen)
USB-conversie met joystick uit de jaren 80: deze originele Cheetah 125-joystick uit de jaren 80 heeft een liefdevolle ombouw gehad met glimmende nieuwe microschakelaars, arcade-knoppen en een Pimoroni Player X-controllerbord. Het heeft nu vier onafhankelijke "vuur" knoppen en maakt verbinding via USB, klaar voor
Draadloze afstandsbediening met 2,4 GHz NRF24L01-module met Arduino - Nrf24l01 4-kanaals / 6-kanaals zenderontvanger voor quadcopter - RC Helikopter - RC-vliegtuig met Arduino: 5 stappen (met afbeeldingen)
Draadloze afstandsbediening met 2,4 GHz NRF24L01-module met Arduino | Nrf24l01 4-kanaals / 6-kanaals zenderontvanger voor quadcopter | RC Helikopter | Rc-vliegtuig met Arduino: een Rc-auto besturen | Quadcopter | Drone | RC vliegtuig | RC-boot, we hebben altijd een ontvanger en zender nodig, stel dat we voor RC QUADCOPTER een 6-kanaals zender en ontvanger nodig hebben en dat type TX en RX is te duur, dus we gaan er een maken op onze
Digger' spelen met een joystick!: 4 stappen
Hoe speel je 'Digger' met een joystick!: Een paar jaar geleden besloot ik mijn vader te verrassen door de allereerste game te vinden die hij speelde, waarvan hij dacht dat die van de wereld was verdwenen. Digger!Digger werd in 1983 geproduceerd door Windmill Software, een bedrijf gevestigd in Toronto, Canada. Het draaide op pc's su