Taula de continguts:

Joc de plataformes controlat per Arduino amb joystick i receptor IR: 3 passos (amb imatges)
Joc de plataformes controlat per Arduino amb joystick i receptor IR: 3 passos (amb imatges)

Vídeo: Joc de plataformes controlat per Arduino amb joystick i receptor IR: 3 passos (amb imatges)

Vídeo: Joc de plataformes controlat per Arduino amb joystick i receptor IR: 3 passos (amb imatges)
Vídeo: Изучаем iOS: создайте собственное приложение с помощью Objective-C! от Тянью Лю 2024, Desembre
Anonim
Joc de plataformes controlat per Arduino amb joystick i receptor IR
Joc de plataformes controlat per Arduino amb joystick i receptor IR

Avui utilitzarem un microcontrolador Arduino per controlar un simple joc de plataformes basat en C #. Estic fent servir l'Arduino per prendre l'entrada d'un mòdul de joystick i enviar aquesta entrada a l'aplicació C # que escolta i descodifica l'entrada mitjançant una connexió sèrie. Tot i que no necessiteu cap experiència prèvia en la creació de videojocs per completar el projecte, pot ser que necessiteu temps per absorbir algunes de les coses que passen al "bucle del joc", que parlarem més endavant.

Per completar aquest projecte, necessitareu:

  • Comunitat de Visual Studio
  • Un Arduino Uno (o similar)
  • Un mòdul de controlador de joystick
  • Paciència

Si esteu a punt per començar, continueu!

Pas 1: connecteu el joystick i el LED IR

Connecteu el joystick i el LED IR
Connecteu el joystick i el LED IR
Connecteu el joystick i el LED IR
Connecteu el joystick i el LED IR

Aquí, la connexió és bastant senzilla. He inclòs diagrames que mostren només el joystick connectat, així com la configuració que estic fent servir, que inclou el joystick més un LED d’infrarojos per controlar el joc amb un control remot, que inclou molts kits Arduino. Això és opcional, però em va semblar una bona idea poder fer jocs sense fils.

Els pins utilitzats a la configuració són:

  • A0 (analògic) <- Eix horitzontal o X.
  • A1 (analògic) <- Eix vertical o eix Y
  • Pin 2 <- Entrada del commutador del joystick
  • Pin 2 <- Entrada LED d'infrarojos
  • VCC <- 5V
  • Terra
  • Terra # 2

Pas 2: creeu un esbós nou

Creeu un esbós nou
Creeu un esbós nou

Començarem creant el nostre fitxer de croquis Arduino. Això enquesta el joystick per obtenir canvis i envia aquests canvis al programa C # cada diversos mil·lisegons. En un videojoc real, comprovaríem si hi havia entrades del port sèrie en un bucle de joc, però vaig començar el joc com un experiment, de manera que la freqüència de fotogrames es basa en realitat en el nombre d'esdeveniments del port sèrie. De fet, havia començat el projecte en el projecte germana Arduino, Processament, però resulta que era molt, molt més lent i no podia gestionar el nombre de caixes a la pantalla.

Per tant, primer creeu un nou Sketch al programa editor de codi Arduino. Mostraré el meu codi i després explicaré què fa:

#include "IRremote.h"

// variables IR int receptor = 3; // Pin de senyal del receptor IR IRrecv irrecv (receptor); // crear instància de resultats "irrecv" decode_results; // crear instància de 'decode_results' // Joystick / variables del joc int xPos = 507; int yPos = 507; byte joyXPin = A0; byte joyYPin = A1; byte joySwitch = 2; byte volàtil clickCounter = -1; int minMoveHigh = 530; int minMoveLow = 490; int currentSpeed = 550; // Per defecte = una velocitat mitjana int speedIncrement = 25; // Quantitat per augmentar / disminuir la velocitat amb l'entrada Y sense signar corrent llarg = 0; // Manté la marca de temps actual int wait = 40; // ms per esperar entre missatges [Nota: espera inferior = velocitat de fotogrames més ràpida] botó volàtil bools Pressionat = fals; // Mesura si es prem el botó void setup () {Serial.begin (9600); pinMode (joySwitch, INPUT_PULLUP); attachInterrupt (0, saltar, CAURE); actual = millis (); // Configureu l'hora actual // Configureu el receptor d'infrarojos: irrecv.enableIRIn (); // Inicieu el receptor} // setup void loop () {int xMovement = analogRead (joyXPin); int yPos = analogRead (joyYPin); // Gestioneu el moviment del joystick X independentment del moment: if (xMovement> minMoveHigh || xMovement current + wait) {currentSpeed = yPos> minMoveLow && yPos <minMoveHigh // Si només es mogués una mica …? currentSpeed // … només cal retornar la velocitat actual: getSpeed (yPos); // Canvieu yPos només si el joystick es va moure significativament // int distance =; Serial.print ((String) xPos + "," + (String) yPos + ',' + (String) currentSpeed + '\ n'); actual = millis (); }} // loop int getSpeed (int yPos) {// Els valors negatius indiquen que el joystick s'ha mogut cap amunt si (yPos 1023? 1023: currentSpeed + speedIncrement;} else if (yPos> minMoveHigh) // Interpretat "Down" {// Protegeix de passant per sota de 0 torna currentSpeed - speedIncrement <0? 0: currentSpeed - speedIncrement;}} // getSpeed void jump () {buttonPressed = true; // Indica el botó que es premia}} // jump // Quan es prem un botó a la remot, gestiona la resposta adequada void translateIR (decode_results results) // pren accions basades en el codi IR rebut {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 (" altre botó "); break;} // End switch} // END translateIR

Vaig intentar crear el codi perquè s’explicés per si mateix, però hi ha algunes coses que val la pena esmentar. Una cosa que vaig intentar explicar era en les línies següents:

int minYMoveUp = 520;

int minYMoveDown = 500;

Quan el programa s’executa, l’entrada analògica del joystick tendeix a saltar, normalment es manté al voltant de 507. Per corregir-ho, l’entrada no canvia tret que sigui més gran que minYMoveUp o més petita que minYMoveDown.

pinMode (joySwitch, INPUT_PULLUP);

attachInterrupt (0, saltar, CAURE);

El mètode attachInterrupt () ens permet interrompre el bucle normal en qualsevol moment, de manera que podem accedir a l'entrada, com prémer el botó quan es fa clic al botó del joystick. Aquí, hem adjuntat la interrupció a la línia anterior, mitjançant el mètode pinMode (). Una nota important aquí és que per connectar una interrupció a l'Arduino Uno, heu d'utilitzar el pin 2 o 3. Altres models utilitzen pins d'interrupció diferents, de manera que és possible que hàgiu de comprovar quins pins utilitza el vostre model al lloc web d'Arduino. El segon paràmetre és per al mètode de devolució de trucada, aquí anomenat ISR o una "rutina de servei d'interrupció". No hauria de prendre cap paràmetre ni retornar res.

Serial.print (…)

Aquesta és la línia que enviarà les nostres dades al joc C #. Aquí, enviem la lectura de l’eix X, la lectura de l’eix Y i una variable de velocitat al joc. Aquestes lectures es poden ampliar per incloure altres entrades i lectures per fer el joc més interessant, però aquí només en farem servir un parell.

Si esteu preparat per provar el vostre codi, pengeu-lo a l'Arduino i premeu [Maj] + [Ctrl] + [M] per obrir el monitor sèrie i veure si obteniu alguna sortida. Si rebeu dades de l'Arduino, estem preparats per passar a la porció C # del codi …

Pas 3: creeu el projecte C #

Per mostrar els nostres gràfics, inicialment vaig començar un projecte a Processament, però més tard vaig decidir que seria massa lent mostrar tots els objectes que hem de mostrar. Per tant, vaig optar per utilitzar C #, que va resultar ser molt més suau i més sensible a l’hora de gestionar les nostres aportacions.

Per a la part C # del projecte, és millor descarregar el fitxer.zip i extreure'l a la seva pròpia carpeta i modificar-lo. Hi ha dues carpetes al fitxer zip. Per obrir el projecte a Visual Studio, introduïu la carpeta RunnerGame_CSharp a l'Explorador de Windows. Aquí, feu doble clic al fitxer.sln (solució) i VS carregarà el projecte.

Hi ha algunes classes diferents que he creat per al joc. No entraré en tots els detalls sobre cada classe, però donaré una visió general de què serveixen les classes principals.

La classe Box

Vaig crear la classe de caixa per permetre-vos crear objectes rectangles senzills que es puguin dibuixar a la pantalla en forma de Windows. La idea és crear una classe que es pugui ampliar mitjançant altres classes que vulguin dibuixar algun tipus de gràfics. La paraula clau "virtual" s'utilitza perquè altres classes puguin anul·lar-les (mitjançant la paraula clau "anul·lar"). D’aquesta manera, podem obtenir el mateix comportament per a la classe Player i la classe Platform quan ho necessitem, i també modificar els objectes com necessitem.

No us preocupeu massa per totes les propietats i truqueu trucades. Vaig escriure aquesta classe per poder-la ampliar per a qualsevol joc o programa de gràfics que pogués voler fer en el futur. Si heu de dibuixar un rectangle sobre la marxa, no haureu d’escriure una classe tan gran com aquesta. La documentació C # conté bons exemples de com fer-ho.

Tanmateix, exposaré algunes de les lògiques de la meva classe "Box":

boole virtual públic IsCollidedX (quadre otherObject) {…}

Aquí comprovem si hi ha col·lisions amb objectes en direcció X, perquè el jugador només ha de comprovar si hi ha col·lisions en la direcció Y (amunt i avall) si està alineado amb la pantalla.

boole virtual públic IsCollidedY (quadre otherObject) {…}

Quan estem a sobre o sota un altre objecte de joc, comprovem si hi ha col·lisions.

boole virtual públic IsCollided (quadre otherObject) {…}

Això combina les col·lisions X i Y, retornant si algun objecte està col·lisionat amb aquest.

buit virtual públic OnPaint (gràfics gràfics) {…}

Mitjançant el mètode anterior, passem qualsevol objecte gràfic i l’utilitzem mentre s’executa el programa. Creem qualsevol rectangle que pugui haver de ser dibuixat. Tot i això, es podria utilitzar per a diverses animacions. Als nostres propòsits, els rectangles funcionaran bé tant per a les plataformes com per al jugador.

La classe de personatges

La classe de caràcters amplia la meva classe de caixa, de manera que tenim certa física fora de la caixa. Vaig crear el mètode "CheckForCollisions" per comprovar ràpidament totes les plataformes que hem creat per a una col·lisió. El mètode "Jump" estableix la velocitat ascendent del jugador a la variable JumpSpeed, que després es modifica fotograma a fotograma a la classe MainWindow.

Les col·lisions es gestionen lleugerament de manera diferent que a la classe Box. En aquest joc vaig decidir que si saltem cap amunt, podem saltar per una plataforma, però atraparà el nostre jugador en baixar si xoca amb ella.

La classe de la plataforma

En aquest joc, només faig servir el constructor d’aquesta classe que pren com a entrada una coordenada X, calculant totes les ubicacions X de les plataformes de la classe MainWindow. Cada plataforma es configura a una coordenada Y aleatòria des de 1/2 de la pantalla fins a 3/4 de l'alçada de la pantalla. L'alçada, l'amplada i el color també es generen a l'atzar.

La classe MainWindow

Aquí és on posem tota la lògica que s’ha d’utilitzar mentre el joc s’executa. En primer lloc, al constructor, imprimim tots els ports COM disponibles al programa.

foreach (port de cadena a SerialPort. GetPortNames ())

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

Triem en quin acceptarem les comunicacions, segons el port que ja utilitzi el vostre Arduino:

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

Presteu molta atenció a l'ordre: SerialPort. GetPortNames () [2]. El [2] significa quin port sèrie s'ha d'utilitzar. Per exemple, si el programa imprimís "COM1, COM2, COM3", escoltaríem a COM3 perquè la numeració comença a 0 a la matriu.

També al constructor, creem totes les plataformes amb espaiat i posició semi-aleatòria en la direcció Y a la pantalla. Totes les plataformes s’afegeixen a un objecte List, que a C # és simplement una manera molt fàcil d’utilitzar i eficient de gestionar una estructura de dades semblant a una matriu. A continuació, creem el jugador, que és el nostre objecte de caràcter, establim la puntuació a 0 i posem GameOver a fals.

private static void DataReceived (remitent d'objectes, SerialDataReceivedEventArgs e)

Aquest és el mètode que s’anomena quan es reben dades al port sèrie. Aquí és on apliquem tota la nostra física, decidim si volem mostrar el joc, moure les plataformes, etc. Si alguna vegada heu creat un joc, generalment teniu el que s'anomena "bucle de joc", que s'anomena cada vegada que el marc refresca. En aquest joc, el mètode DataReceived actua com el bucle del joc, només manipulant la física a mesura que es reben dades del controlador. Potser hauria funcionat millor configurar un temporitzador a la finestra principal i actualitzar els objectes en funció de les dades rebudes, però com que es tracta d’un projecte d’Arduino, volia fer un joc que realment s’executés en funció de les dades que en provenien..

En conclusió, aquesta configuració proporciona una bona base per expandir el joc a quelcom usable. Tot i que la física no és del tot perfecta, funciona prou bé per als nostres propòsits, que és utilitzar l’Arduino per a allò que tothom li agrada: jugar a jocs.

Recomanat: