Innholdsfortegnelse:

Arduino-kontrollert plattformspill med joystick og IR-mottaker: 3 trinn (med bilder)
Arduino-kontrollert plattformspill med joystick og IR-mottaker: 3 trinn (med bilder)

Video: Arduino-kontrollert plattformspill med joystick og IR-mottaker: 3 trinn (med bilder)

Video: Arduino-kontrollert plattformspill med joystick og IR-mottaker: 3 trinn (med bilder)
Video: Starting a Sidecar MIDI Controller to expand the Ibanez IMG2010 MC1 Guitar to MIDI Converter system 2024, November
Anonim
Arduino-kontrollert plattformspill med joystick og IR-mottaker
Arduino-kontrollert plattformspill med joystick og IR-mottaker

I dag skal vi bruke en Arduino mikrokontroller for å kontrollere et enkelt C#-basert plattformspill. Jeg bruker Arduino til å ta inngang fra en joystick -modul, og sende denne inngangen til C# -programmet som lytter og dekoder input over en seriell tilkobling. Selv om du ikke trenger noen tidligere erfaring med å bygge videospill for å fullføre prosjektet, kan det ta litt tid å absorbere noen av tingene som skjer i "spillløkken", som vi vil diskutere senere.

For å fullføre dette prosjektet trenger du:

  • Visual Studio Community
  • En Arduino Uno (eller lignende)
  • En styrespakskontrollmodul
  • Tålmodighet

Hvis du er klar til å begynne, fortsett!

Trinn 1: Koble til styrespaken og IR -LED

Koble til styrespaken og IR -LED
Koble til styrespaken og IR -LED
Koble til styrespaken og IR -LED
Koble til styrespaken og IR -LED

Her er tilkoblingen ganske enkel. Jeg har inkludert diagrammer som viser bare styrespaken koblet til, samt oppsettet jeg bruker, som inkluderer joysticken pluss en infrarød LED for å kontrollere spillet med en fjernkontroll, som følger med mange Arduino -sett. Dette er valgfritt, men det virket som en kul idé å kunne spille trådløst.

Pinnene som ble brukt i oppsettet er:

  • A0 (analog) <- Horisontal eller X-akse
  • A1 (analog) <- Vertikal eller Y-akse
  • Pin 2 <- Joystick Switch inngang
  • Pin 2 <- Infrarød LED-inngang
  • VCC <- 5V
  • Bakke
  • Bakken #2

Trinn 2: Lag en ny skisse

Lag en ny skisse
Lag en ny skisse

Vi starter med å lage vår Arduino skissefil. Dette undersøker styrespaken for endringer, og sender endringene til C# -programmet hvert flere millisekund. I et faktisk videospill ville vi sjekke seriell port i en spillløkke for input, men jeg begynte spillet som et eksperiment, så frameraten er faktisk basert på antall hendelser på serieporten. Jeg hadde faktisk startet prosjektet i Arduino søsterprosjektet, Processing, men det viser seg at det var mye, mye tregere og ikke kunne håndtere antall bokser på skjermen.

Så, opprett først en ny skisse i Arduino -koderedigeringsprogrammet. Jeg vil vise koden min og deretter forklare hva den gjør:

#include "IRremote.h"

// IR -variabler int mottaker = 3; // Signalpinne av IR -mottaker IRrecv irrecv (mottaker); // lage forekomst av 'irrecv' decode_results resultater; // opprett forekomst av 'decode_results' // Joystick/game variables int xPos = 507; int yPos = 507; byte joyXPin = A0; byte joyYPin = A1; byte joySwitch = 2; flyktig byte clickCounter = -1; int minMoveHigh = 530; int minMoveLow = 490; int currentSpeed = 550; // Standard = gjennomsnittlig hastighet int speedIncrement = 25; // Mengde for å øke/redusere hastigheten med Y -inngang usignert langstrøm = 0; // Holder gjeldende tidsstempel int wait = 40; // ms for å vente mellom meldingene [Merk: lavere ventetid = raskere framerate] volatile bool buttonPressed = false; // Måler hvis du trykker på knappen void setup () {Serial.begin (9600); pinMode (joySwitch, INPUT_PULLUP); attachInterrupt (0, hopp, FALLING); nåværende = millis (); // Konfigurer gjeldende tid // Konfigurer infrarød mottaker: irrecv.enableIRIn (); // Start mottakeren} // setup void loop () {int xMovement = analogRead (joyXPin); int yPos = analogRead (joyYPin); // Håndter joystick X -bevegelsen uavhengig av timing: hvis (xMovement> minMoveHigh || xMovement current + wait) {currentSpeed = yPos> minMoveLow && yPos <minMoveHigh // Hvis bare flyttet litt …? currentSpeed // … bare returner gjeldende hastighet: getSpeed (yPos); // Endre bare yPos hvis joysticken flyttes betydelig // int distance =; Serial.print ((String) xPos + "," + (String) yPos + ',' + (String) currentSpeed + '\ n'); nåværende = millis (); }} // loop int getSpeed (int yPos) {// Negative verdier indikerer joysticken flyttet opp hvis (yPos 1023? 1023: currentSpeed + speedIncrement;} annet hvis (yPos> minMoveHigh) // Tolkes "ned" {// Beskytt mot går under 0 return currentSpeed - speedIncrement <0? 0: currentSpeed - speedIncrement;}} // getSpeed void jump () {buttonPressed = true; // Angi at knappen ble trykket.} // hopp // Når en knapp trykkes på fjernkontroll, håndter riktig svar void translateIR (decode_results results) // tar handling basert på mottatt IR -kode {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 (" annen knapp "); pause;} // Sluttbryter} // SLUTT translateIR

Jeg prøvde å lage koden for å være mest selvforklarende, men det er noen ting som er verdt å nevne. En ting jeg prøvde å gjøre rede for var i følgende linjer:

int minYMoveUp = 520;

int minYMoveDown = 500;

Når programmet kjører, har den analoge inngangen fra styrespaken en tendens til å hoppe rundt, vanligvis på rundt 507. For å korrigere dette endres ikke inngangen med mindre den er større enn minYMoveUp, eller mindre enn minYMoveDown.

pinMode (joySwitch, INPUT_PULLUP);

attachInterrupt (0, hopp, FALLING);

Ved hjelp av attachInterrupt () -metoden kan vi når som helst avbryte den normale sløyfen, slik at vi kan ta innspill, for eksempel trykk på knappen når du klikker på styrespaken. Her har vi festet avbruddet i linjen før det, ved hjelp av pinMode () -metoden. En viktig merknad her er at for å feste en avbrudd på Arduino Uno, må du bruke enten pin 2 eller 3. Andre modeller bruker forskjellige interrupt pins, så du må kanskje sjekke hvilke pins din modell bruker på Arduino nettstedet. Den andre parameteren er for tilbakeringingsmetoden, her kalt en ISR eller en "Interrupt Service Routine". Det skal ikke ta noen parametere eller returnere noe.

Serial.print (…)

Dette er linjen som sender dataene våre til C# -spillet. Her sender vi avlesning av X-aksen, avlesning av Y-aksen og en hastighetsvariabel til spillet. Disse avlesningene kan utvides til å inkludere andre innganger og avlesninger for å gjøre spillet mer interessant, men her vil vi bare bruke et par.

Hvis du er klar til å teste koden, laster du den opp til Arduino og trykker på [Shift] + [Ctrl] + [M] for å åpne den serielle skjermen og se om du får utgang. Hvis du mottar data fra Arduino, er vi klare til å gå videre til C# -delen av koden …

Trinn 3: Opprett C# -prosjektet

For å vise grafikken vår startet jeg først et prosessprosjekt, men bestemte meg senere for at det ville være for sakte å vise alle objektene vi må vise. Så jeg valgte å bruke C#, som viste seg å være mye jevnere og mer lydhør når vi håndterte innspillene våre.

For C# -delen av prosjektet er det best å bare laste ned.zip -filen og pakke den ut til sin egen mappe, og deretter endre den. Det er to mapper i zip -filen. For å åpne prosjektet i Visual Studio, skriv inn mappen RunnerGame_CSharp i Windows Utforsker. Dobbeltklikk på.sln-filen (løsning), og VS vil laste inn prosjektet.

Det er noen forskjellige klasser jeg laget for spillet. Jeg vil ikke gå inn på alle detaljene om hver klasse, men jeg vil gi en oversikt over hva hovedklassene er for.

Boksklassen

Jeg opprettet bokseklassen slik at du kan lage enkle rektangelobjekter som kan tegnes på skjermen i et Windows-skjema. Ideen er å lage en klasse som kan utvides ved hjelp av andre klasser som kanskje vil tegne en slags grafikk. Det "virtuelle" søkeordet brukes slik at andre klasser kan overstyre dem (ved å bruke søkeordet "overstyr"). På den måten kan vi få samme oppførsel for Player -klassen og Platform -klassen når vi trenger det, og også endre objektene slik vi trenger det.

Ikke bekymre deg for mye om alle egenskapene og trekk samtaler. Jeg skrev denne klassen slik at jeg kunne utvide den til alle spill eller grafikkprogrammer jeg kanskje vil lage i fremtiden. Hvis du bare trenger å tegne et rektangel i farten, trenger du ikke å skrive ut en stor klasse som denne. C# -dokumentasjonen har gode eksempler på hvordan du gjør dette.

Imidlertid vil jeg legge ut noen av logikken i min "Box" -klasse:

offentlig virtuell bool IsCollidedX (Box otherObject) {…}

Her sjekker vi kollisjoner med objekter i X-retningen, fordi spilleren bare trenger å se etter kollisjoner i Y-retningen (opp og ned) hvis han er stilt opp med den på skjermen.

offentlig virtuell bool IsCollidedY (Box otherObject) {…}

Når vi er over eller under et annet spillobjekt, ser vi etter Y -kollisjoner.

offentlig virtuell bool IsCollided (Box otherObject) {…}

Dette kombinerer X- og Y -kollisjoner, og returnerer om et objekt blir kollidert med dette.

offentlig virtuelt tomrom OnPaint (grafikkgrafikk) {…}

Ved å bruke metoden ovenfor, sender vi ethvert grafikkobjekt inn og bruker det mens programmet kjører. Vi lager alle rektangler som må trekkes. Dette kan imidlertid brukes til en rekke animasjoner. For våre formål vil rektangler gjøre det bra for både plattformene og spilleren.

Karakterklassen

Character -klassen utvider Box -klassen min, så vi har viss fysikk ut av esken. Jeg opprettet "CheckForCollisions" -metoden for å raskt kontrollere alle plattformene vi har opprettet for en kollisjon. "Jump" -metoden setter spillerens hastighet oppover til JumpSpeed-variabelen, som deretter blir endret bilde for bilde i MainWindow-klassen.

Kollisjoner håndteres litt annerledes her enn i Box -klassen. Jeg bestemte meg i dette spillet at hvis vi hopper oppover, kan vi hoppe gjennom en plattform, men det vil fange spilleren vår på vei ned hvis den kolliderer med den.

Plattformklassen

I dette spillet bruker jeg bare konstruktøren av denne klassen som tar en X-koordinat som inngang, som beregner alle plattformenes X-steder i MainWindow-klassen. Hver plattform er satt opp med en tilfeldig Y-koordinat fra 1/2 skjermen til 3/4 av skjermens høyde. Høyden, bredden og fargen genereres også tilfeldig.

MainWindow -klassen

Det er her vi legger all logikken som skal brukes mens spillet er i gang. Først, i konstruktøren, skriver vi ut alle COM -portene som er tilgjengelige for programmet.

foreach (strengport i SerialPort. GetPortNames ())

Console. WriteLine ("TILGJENGELIGE PORTER:" + port);

Vi velger hvilken vi vil godta kommunikasjon på, i henhold til hvilken port din Arduino allerede bruker:

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

Vær nøye med kommandoen: SerialPort. GetPortNames () [2]. [2] angir hvilken serieport som skal brukes. For eksempel, hvis programmet skrev ut "COM1, COM2, COM3", ville vi lytte på COM3 fordi nummereringen begynner med 0 i matrisen.

Også i konstruktøren lager vi alle plattformene med semi-tilfeldig avstand og plassering i Y-retningen på skjermen. Alle plattformene legges til i et listeobjekt, som i C# ganske enkelt er en veldig brukervennlig og effektiv måte å administrere en matriselignende datastruktur. Vi oppretter deretter spilleren, som er vårt karakterobjekt, setter poengsummen til 0 og setter GameOver til false.

private static void DataReceived (objektavsender, SerialDataReceivedEventArgs e)

Dette er metoden som kalles når data mottas på serieporten. Det er her vi bruker all vår fysikk, bestemmer om vi skal vise spillet over, flytte plattformene osv. Hvis du noen gang har bygget et spill, har du vanligvis det som kalles en "game loop", som kalles hver gang rammen oppdateres. I dette spillet fungerer DataReceived -metoden som spillsløyfen, og manipulerer bare fysikken ettersom data mottas fra kontrolleren. Det kunne ha fungert bedre å sette opp en timer i hovedvinduet og oppdatere objektene basert på mottatte data, men siden dette er et Arduino -prosjekt, ønsket jeg å lage et spill som faktisk kjørte basert på dataene som kom inn fra det.

Avslutningsvis gir dette oppsettet et godt grunnlag for å utvide spillet til noe brukbart. Selv om fysikken ikke er helt perfekt, fungerer den godt nok til våre formål, det vil si å bruke Arduino til noe alle liker: å spille spill!

Anbefalt: