Përmbajtje:

Lojë Platformer e kontrolluar nga Arduino me xhojstik dhe marrës IR: 3 hapa (me fotografi)
Lojë Platformer e kontrolluar nga Arduino me xhojstik dhe marrës IR: 3 hapa (me fotografi)

Video: Lojë Platformer e kontrolluar nga Arduino me xhojstik dhe marrës IR: 3 hapa (me fotografi)

Video: Lojë Platformer e kontrolluar nga Arduino me xhojstik dhe marrës IR: 3 hapa (me fotografi)
Video: ЛЕГКАЯ карточка для чистки картриджей для видеоигр своими руками #shorts 2024, Dhjetor
Anonim
Lojë me platformë të kontrolluar nga Arduino me xhojstik dhe marrës IR
Lojë me platformë të kontrolluar nga Arduino me xhojstik dhe marrës IR

Sot, ne do të përdorim një mikrokontrollues Arduino për të kontrolluar një lojë të thjeshtë platformer të bazuar në C#. Unë jam duke përdorur Arduino për të marrë të dhëna nga një modul levë, dhe për ta dërguar atë të dhëna në aplikacionin C# i cili dëgjon dhe deshifron hyrjen mbi një lidhje Seriale. Edhe pse nuk keni nevojë për ndonjë përvojë të mëparshme në ndërtimin e lojërave video për të përfunduar projektin, mund të kërkojë ca kohë për të absorbuar disa nga gjërat që po ndodhin në "lakun e lojës", për të cilat do të diskutojmë më vonë.

Për të përfunduar këtë projekt, do t'ju duhet:

  • Komuniteti i Studio Visual
  • Një Arduino Uno (ose i ngjashëm)
  • Një modul kontrollues levë
  • Durimi

Nëse jeni gati për të filluar, vazhdoni!

Hapi 1: Lidhni Joystick dhe IR LED

Lidhni xhojstikun dhe IR LED
Lidhni xhojstikun dhe IR LED
Lidhni xhojstikun dhe IR LED
Lidhni xhojstikun dhe IR LED

Këtu, lidhja është mjaft e thjeshtë. Unë kam përfshirë diagrame që tregojnë vetëm levën e lidhur, si dhe konfigurimin që po përdor, i cili përfshin levën plus një LED infra të kuqe për kontrollin e lojës me një telekomandë, e cila vjen me shumë komplete Arduino. Kjo është opsionale, por dukej si një ide interesante të jesh në gjendje të bësh lojëra pa tel.

Kunjat e përdorura në konfigurim janë:

  • A0 (analoge) <- Boshti horizontal ose X-aks
  • A1 (analoge) <- boshti vertikal ose Y-ja
  • Pin 2 <- Joystick Switch input
  • Pin 2 <- Hyrje LED me rreze infra të kuqe
  • VCC <- 5V
  • Toke
  • Terreni #2

Hapi 2: Krijoni një Skicë të Re

Krijoni një Skicë të Re
Krijoni një Skicë të Re

Ne do të fillojmë me krijimin e skedarit tonë të skicës Arduino. Kjo anketon levën për ndryshimet dhe i dërgon ato ndryshime në programin C# çdo disa milisekonda. Në një lojë video të vërtetë, ne do të kontrollonim portën serike në një lak loje për hyrje, por e fillova lojën si një eksperiment, kështu që shpejtësia e kornizës në fakt bazohet në numrin e ngjarjeve në portën serike. Unë në fakt e kisha filluar projektin në projektin motër Arduino, Përpunimi, por rezulton se ishte shumë, shumë më i ngadalshëm dhe nuk mund të përballoja numrin e kutive në ekran.

Pra, së pari krijoni një Skicë të re në programin e redaktuesit të kodit Arduino. Unë do të tregoj kodin tim dhe pastaj do të shpjegoj se çfarë bën:

#përfshi "IRremote.h"

// Variablat IR brenda marrësit = 3; // Pin Sinjali i marrësit IR IRrecv irrecv (marrës); // krijoni një shembull të rezultateve të 'uncrecv' të deshifrimit të rezultateve; // krijoni shembullin e 'deshifroj_rezultatet' // Joystick/variablat e lojës int xPos = 507; int yPos = 507; byte joyXPin = A0; byte joyYPin = A1; byte joySwitch = 2; bajt i paqëndrueshëm clickCounter = -1; int minMoveHigh = 530; int minMoveLow = 490; int currentSpeed = 550; // Default = një shpejtësi mesatare int speedIncrement = 25; // Shuma për të rritur/ulur shpejtësinë me hyrje Y rrymë e gjatë e panënshkruar = 0; // Mban kohëzgjatjen aktuale kohore në pritje = 40; // ms për të pritur midis mesazheve [Shënim: pritja më e ulët = shpejtësia e kornizës më e shpejtë] butoni i paqëndrueshëm i boolPressed = false; // Matni nëse butoni shtypet void setup () {Serial.begin (9600); pinMode (joySwitch, INPUT_PULLUP); attachInterrupt (0, kërcim, Rënie); aktuale = milis (); // Konfiguro kohën aktuale // Konfiguro marrësin infra të kuqe: irrecv.enableIRIn (); // Nis marrësin} // setup void loop () {int xMovement = analogRead (joyXPin); int yPos = analogRead (joyYPin); // Trajtoni lëvizjen Joystick X pavarësisht nga koha: nëse (xMovement> minMoveHigh || xMovement current + wait) {currentSpeed = yPos> minMoveLow && yPos <minMoveHigh // Nëse lëviz vetëm pak…? currentSpeed //… thjesht ktheni shpejtësinë aktuale: getSpeed (yPos); // Ndryshoni yPos vetëm nëse levë lëvizi ndjeshëm // int distanca =; Serial.print ((String) xPos + "," + (String) yPos + ',' + (String) currentSpeed + '\ n'); aktuale = milis (); }} // loop int getSpeed (int yPos) {// Vlerat negative tregojnë që Joystick u ngrit nëse (yPos 1023? 1023: currentSpeed + speedIncrement;} tjetër nëse (yPos> minMoveHigh) // Interpretohet "Poshtë" {// Mbrojeni nga duke shkuar nën 0 kthimi currentSpeed - speedIncrement <0? 0: currentSpeed - speedIncrement;}} // getSpeed void jump () {buttonPressed = true; // Butoni tregues u shtyp.} // kërce // Kur një buton shtypet në të largëta, trajtoni përgjigjen e duhur void translateIR (rezultatet e deshifrimit_resultat) // ndërmerr veprime bazuar në kodin IR të marrë {switch (results.value) {case 0xFF18E7: //Serial.println("2 "); currentSpeed += speedIncrement * 2; pushim; rasti 0xFF10EF: //Serial.println("4 "); xPos = -900; thyerje; rasti 0xFF38C7: //Serial.println("5"); jump (); pushim; rasti 0xFF5AA5: // Serial. println ("6"); xPos = 900; pushim; rast 0xFF4AB5: //Serial.println("8 "); currentSpeed -= speedIncrement * 2; pushim; parazgjedhje: //Serial.println (" buton tjetër "); pushim;} // Ndërprerësi i përfundimit} // END translateIR

Unë u përpoqa të krijoja kodin që të ishte kryesisht vetë-shpjegues, por ka disa gjëra që vlen të përmenden. Një gjë për të cilën u përpoqa të jepja llogari ishte në rreshtat e mëposhtëm:

int minYMoveUp = 520;

int minYMoveDown = 500;

Kur programi po funksionon, hyrja analoge nga levë tenton të kërcejë, zakonisht duke qëndruar në rreth 507. Për ta korrigjuar këtë, hyrja nuk ndryshon nëse nuk është më e madhe se minYMoveUp, ose më e vogël se minYMoveDown.

pinMode (joySwitch, INPUT_PULLUP);

attachInterrupt (0, kërcim, Rënie);

Metoda attachInterrupt () na lejon të ndërpresim ciklin normal në çdo kohë, në mënyrë që të marrim të dhëna, si shtypja e butonit kur klikohet butoni i levës. Këtu, ne kemi bashkangjitur ndërprerjen në rreshtin para saj, duke përdorur metodën pinMode (). Një shënim i rëndësishëm këtu është se për të bashkangjitur një ndërprerje në Arduino Uno, duhet të përdorni ose pin 2 ose 3. Modele të tjera përdorin kunja të ndryshme ndërprerjeje, kështu që mund t'ju duhet të kontrolloni cilat kunja përdor modeli juaj në faqen e internetit të Arduino. Parametri i dytë është për metodën e thirrjes, e quajtur këtu një ISR ose një "Rutinë e Shërbimit të Ndërprerë". Nuk duhet të marrë asnjë parametër ose të kthejë asgjë.

Serial.print (…)

Kjo është linja e cila do të dërgojë të dhënat tona në lojën C#. Këtu, ne dërgojmë leximin e boshtit X, leximin e boshtit Y dhe një ndryshore shpejtësie në lojë. Këto lexime mund të zgjerohen për të përfshirë hyrje dhe lexime të tjera për ta bërë lojën më interesante, por këtu, ne do të përdorim vetëm një çift.

Nëse jeni gati për të testuar kodin tuaj, ngarkojeni atë në Arduino dhe shtypni [Shift] + [Ctrl] + [M] për të hapur monitorin serik dhe shikoni nëse po merrni ndonjë dalje. Nëse jeni duke marrë të dhëna nga Arduino, ne jemi gati të kalojmë në pjesën C# të kodit…

Hapi 3: Krijoni projektin C#

Për të shfaqur grafikat tona, fillimisht fillova një projekt në Përpunim, por më vonë vendosa se do të ishte shumë e ngadaltë për të treguar të gjitha objektet që na duhen për të shfaqur. Kështu, unë zgjodha të përdor C#, i cili doli të ishte shumë më i qetë dhe më i përgjegjshëm kur trajtonim të dhënat tona.

Për pjesën C# të projektit, është mirë që thjesht të shkarkoni skedarin.zip dhe ta nxirrni në dosjen e vet, pastaj ta modifikoni. Ka dy dosje në skedarin zip. Për të hapur projektin në Visual Studio, futni dosjen RunnerGame_CSharp në Windows Explorer. Këtu, klikoni dy herë skedarin.sln (zgjidhje) dhe VS do të ngarkojë projektin.

Ka disa klasa të ndryshme që kam krijuar për lojën. Unë nuk do të hyj në të gjitha detajet për secilën klasë, por do të jap një përmbledhje të asaj për të cilën janë klasat kryesore.

Klasa e Kutisë

Kam krijuar klasën e kutisë për t'ju lejuar të krijoni objekte të thjeshta drejtkëndëshe që mund të vizatohen në ekran në formën e dritareve. Ideja është të krijoni një klasë që mund të zgjerohet duke përdorur klasa të tjera që mund të duan të vizatojnë një lloj grafike. Fjala kyçe "virtuale" përdoret në mënyrë që klasat e tjera t'i anashkalojnë ato (duke përdorur fjalën kyçe "anulo"). Në atë mënyrë, ne mund të marrim të njëjtën sjellje për klasën Player dhe klasën Platformë kur të kemi nevojë, dhe gjithashtu të modifikojmë objektet ashtu siç kemi nevojë.

Mos u shqetësoni shumë për të gjitha pronat dhe tërheqni thirrje. Unë e shkrova këtë klasë në mënyrë që ta zgjas atë për çdo lojë ose program grafik që mund të dëshiroj të bëj në të ardhmen. Nëse keni nevojë të vizatoni një drejtkëndësh në fluturim, nuk keni pse të shkruani një klasë të madhe si kjo. Dokumentacioni C# ka shembuj të mirë se si ta bëni këtë.

Sidoqoftë, unë do të paraqes disa nga logjikat e klasës sime "Box":

bool virtual publik IsCollidedX (Kutia tjetërObject) {…}

Këtu kontrollojmë për përplasje me objekte në drejtimin X, sepse lojtari duhet vetëm të kontrollojë për përplasje në drejtimin Y (lart e poshtë) nëse është i rreshtuar me të në ekran.

bool publik publik IsCollidedY (Kutia tjetërObject) {…}

Kur jemi mbi ose nën një objekt tjetër loje, ne kontrollojmë për përplasjet Y.

bool publik publik IsCollided (Kutia tjetërObject) {…}

Kjo kombinon përplasjet X dhe Y, duke kthyer nëse ndonjë objekt është përplasur me këtë.

zbrazëti virtuale publike OnPaint (Grafika grafike) {…}

Duke përdorur metodën e mësipërme, ne kalojmë çdo objekt grafik brenda dhe e përdorim ndërsa programi po funksionon. Ne krijojmë ndonjë drejtkëndësh që mund të ketë nevojë të vizatohet. Sidoqoftë, kjo mund të përdoret për një larmi animacionesh. Për qëllimet tona, drejtkëndëshat do të bëjnë mirë si për platformat ashtu edhe për lojtarin.

Klasa e Personazheve

Klasa Karakter zgjeron klasën time Box, kështu që ne kemi fizikë të caktuar jashtë kutisë. Kam krijuar metodën "CheckForCollisions" për të kontrolluar shpejt të gjitha platformat që kemi krijuar për një përplasje. Metoda "Shko" vendos shpejtësinë përpjetë të lojtarit në ndryshoren JumpSpeed, e cila më pas modifikohet kornizë-kornizë në klasën MainWindow.

Përplasjet trajtohen pak më ndryshe këtu sesa në klasën Box. Vendosa në këtë lojë që nëse kërcejmë lart, ne mund të hidhemi nëpër një platformë, por ajo do ta kapë lojtarin tonë në rrugën poshtë nëse përplaset me të.

Klasa e Platformës

Në këtë lojë, unë përdor vetëm konstruktorin e kësaj klase i cili merr një koordinatë X si hyrje, duke llogaritur të gjitha vendndodhjet X të platformave në klasën MainWindow. Çdo platformë është ngritur në një koordinatë Y të rastësishme nga 1/2 e ekranit në 3/4 e lartësisë së ekranit. Lartësia, gjerësia dhe ngjyra gjithashtu krijohen rastësisht.

Klasa MainWindow

Këtu vendosim të gjithë logjikën që do të përdoret gjatë lojës. Së pari, në konstruktorin, ne shtypim të gjitha portet COM të disponueshme për programin.

foreach (porta e vargut në SerialPort. GetPortNames ())

Console. WriteLine ("PORTET E DISPONUESHME:" + port);

Ne zgjedhim se në cilën do të pranojmë komunikimet, sipas cilës portë tashmë përdor Arduino juaj:

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

Kushtojini vëmendje komandës: SerialPort. GetPortNames () [2]. [2] nënkupton cilën port serik të përdorni. Për shembull, nëse programi printonte "COM1, COM2, COM3", ne do të dëgjonim në COM3 sepse numërimi fillon në 0 në grup.

Gjithashtu në konstruktorin, ne krijojmë të gjitha platformat me hapësirë gjysmë të rastësishme dhe vendosje në drejtimin Y në ekran. Të gjitha platformat i shtohen një objekti List, i cili në C# është thjesht një mënyrë shumë miqësore për përdoruesit dhe efikase për të menaxhuar një strukturë të të dhënave të ngjashme me grupin. Ne pastaj krijojmë Player, i cili është objekti ynë Karakter, vendosim rezultatin në 0 dhe vendosim GameOver në false.

zbrazëtira statike private DataReceived (dërguesi i objektit, SerialDataReceivedEventArgs e)

Kjo është metoda e cila quhet kur të dhënat merren në portën Seriale. Kjo është ajo ku ne aplikojmë të gjithë fizikën tonë, vendosim nëse do ta shfaqim lojën, do të zhvendosim platformat, etj. Nëse keni ndërtuar ndonjëherë një lojë, në përgjithësi keni atë që quhet "loop loje", e cila quhet çdo herë kuadër freskon Në këtë lojë, metoda DataReceived vepron si lak i lojës, duke manipuluar vetëm fizikën pasi të dhënat merren nga kontrolluesi. Mund të ketë funksionuar më mirë të vendosni një kohëmatës në dritaren kryesore dhe të rifreskoni objektet bazuar në të dhënat e marra, por meqenëse ky është një projekt Arduino, doja të bëja një lojë që në të vërtetë funksiononte bazuar në të dhënat që vijnë nga ajo Me

Si përfundim, ky konfigurim jep një bazë të mirë për zgjerimin e lojës në diçka të përdorshme. Edhe pse fizika nuk është mjaft e përsosur, ajo funksionon mjaft mirë për qëllimet tona, që është përdorimi i Arduino për diçka që të gjithëve u pëlqen: të luani lojëra!

Recommended: