Съдържание:

Платформерна игра, контролирана от Arduino, с джойстик и IR приемник: 3 стъпки (със снимки)
Платформерна игра, контролирана от Arduino, с джойстик и IR приемник: 3 стъпки (със снимки)

Видео: Платформерна игра, контролирана от Arduino, с джойстик и IR приемник: 3 стъпки (със снимки)

Видео: Платформерна игра, контролирана от Arduino, с джойстик и IR приемник: 3 стъпки (със снимки)
Видео: Введение в LCD2004 ЖК-дисплей с модулем I2C для Arduino 2024, Юни
Anonim
Arduino-контролирана игра на платформер с джойстик и IR приемник
Arduino-контролирана игра на платформер с джойстик и IR приемник

Днес ще използваме микроконтролер Arduino, за да контролираме проста C#базирана игра на платформинг. Използвам Arduino, за да получа вход от модул на джойстик и да изпращам този вход към приложението C#, което слуша и декодира входа през серийна връзка. Въпреки че не се нуждаете от предишен опит в изграждането на видео игри, за да завършите проекта, може да отнеме известно време, за да усвоите някои от нещата, които се случват в „цикъла на играта“, който ще обсъдим по -късно.

За да завършите този проект, ще ви трябва:

  • Общност на Visual Studio
  • Arduino Uno (или подобен)
  • Контролен модул с джойстик
  • Търпение

Ако сте готови да започнете, продължете!

Стъпка 1: Свържете джойстика и IR LED

Свържете джойстика и IR LED
Свържете джойстика и IR LED
Свържете джойстика и IR LED
Свържете джойстика и IR LED

Тук свързването е доста просто. Включих диаграми, показващи само свързания джойстик, както и настройката, която използвам, която включва джойстика плюс инфрачервен светодиод за управление на играта с дистанционно управление, което се предлага с много комплекти Arduino. Това е по избор, но изглеждаше страхотна идея да можете да правите безжични игри.

Пиновете, използвани при настройката, са:

  • A0 (аналогов) <- Хоризонтална или ос X
  • A1 (аналогов) <- Вертикална или Y-ос
  • Pin 2 <- Вход за превключвател на джойстика
  • Pin 2 <- Инфрачервен LED вход
  • VCC <- 5V
  • Земя
  • Основание #2

Стъпка 2: Създайте нова скица

Създайте нова скица
Създайте нова скица

Ще започнем със създаването на нашия скичен файл Arduino. Това оглежда джойстика за промени и изпраща тези промени в програмата на C# на всеки няколко милисекунди. В една истинска видео игра бихме проверили серийния порт в игрален цикъл за въвеждане, но започнах играта като експеримент, така че честотата на кадрите всъщност се основава на броя на събитията на серийния порт. Всъщност бях започнал проекта в сестринския проект Arduino, Processing, но се оказа, че беше много, много по -бавен и не можех да се справя с броя на кутиите на екрана.

Така че, първо създайте нова скица в програмата за редактор на кодове на Arduino. Ще покажа кода си и след това ще обясня какво прави:

#include "IRremote.h"

// IR променливи int приемник = 3; // Сигнален щифт на IR приемник IRrecv unrecv (приемник); // създаване на екземпляр на 'unrecv' decode_results резултати; // създаване на екземпляр на 'decode_results' // Джойстик/игрални променливи int xPos = 507; int yPos = 507; байт joyXPin = A0; байт радостYPin = A1; байт joySwitch = 2; променлив байт clickCounter = -1; int minMoveHigh = 530; int minMoveLow = 490; int currentSpeed = 550; // По подразбиране = средна скорост int speedIncrement = 25; // Сума за увеличаване/намаляване на скоростта с Y вход без знак дълъг ток = 0; // Задържа текуща времева отметка int wait = 40; // ms за изчакване между съобщенията [Забележка: по -ниско изчакване = по -бърз кадър] променлив бутон бутонPressed = false; // Манометър, ако бутонът е натиснат void setup () {Serial.begin (9600); pinMode (joySwitch, INPUT_PULLUP); attachInterrupt (0, скок, FALLING); ток = милис (); // Настройване на текущото време // Настройване на инфрачервен приемник: unrecv.enableIRIn (); // Стартирайте приемника} // настройка на void loop () {int xMovement = analogRead (joyXPin); int yPos = analogRead (joyYPin); // Обработваме движението на джойстика X независимо от времето: if (xMovement> minMoveHigh || xMovement current + wait) {currentSpeed = yPos> minMoveLow && yPos <minMoveHigh // Ако само малко се премести …? currentSpeed //… просто връща текущата скорост: getSpeed (yPos); // Променете yPos само ако джойстикът се е преместил значително // int distance =; Serial.print ((String) xPos + "," + (String) yPos + ',' + (String) currentSpeed + '\ n'); ток = милис (); }} // цикъл int getSpeed (int yPos) {// Отрицателните стойности показват, че джойстикът е преместен нагоре, ако (yPos 1023? 1023: currentSpeed + speedIncrement;} иначе ако (yPos> minMoveHigh) // Интерпретирано "Надолу" {// Защита от преминава под 0 връщане currentSpeed - speedIncrement <0? 0: currentSpeed - speedIncrement;}} // getSpeed void jump () {buttonPressed = true; // Бутонът за индикация е натиснат.} // скок // Когато бутон е натиснат върху дистанционно, обработете правилния отговор void translateIR (decode_results results) // предприема действия въз основа на получен IR код {switch (results.value) {случай 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; регистър 0xFF4AB5: //Serial.println("8 "); currentSpeed -= speedIncrement * 2; break; по подразбиране: //Serial.println (" друг бутон "); break;} // Краен превключвател} // END translateIR

Опитах се да създам кода, който да бъде само обяснителен, но има няколко неща, които си заслужава да бъдат споменати. Едно нещо, което се опитах да обясня, беше в следните редове:

int minYMoveUp = 520;

int minYMoveDown = 500;

Когато програмата работи, аналоговият вход от джойстика има тенденция да прескача, обикновено оставайки на около 507. За да коригира това, входът не се променя, освен ако не е по -голям от minYMoveUp или по -малък от minYMoveDown.

pinMode (joySwitch, INPUT_PULLUP);

attachInterrupt (0, скок, FALLING);

Методът attachInterrupt () ни позволява да прекъсваме нормалния цикъл по всяко време, така че да можем да приемаме въвеждане, като натискане на бутона при щракване на бутона на джойстика. Тук сме прикачили прекъсването в реда преди него, използвайки метода pinMode (). Важна забележка тук е, че за да прикачите прекъсване към Arduino Uno, трябва да използвате или пин 2 или 3. Други модели използват различни щифтове за прекъсване, така че може да се наложи да проверите кои пинове използва вашият модел на уебсайта на Arduino. Вторият параметър е за метода за обратно извикване, наричан тук ISR или „Рутин за прекъсване на услугата“. Не трябва да приема никакви параметри или да връща нищо.

Serial.print (…)

Това е редът, който ще изпрати нашите данни в играта на C#. Тук изпращаме отчитането по оста X, отчитането по оста Y и променлива на скоростта в играта. Тези показания могат да бъдат разширени, за да включват други входове и показания, за да направят играта по -интересна, но тук ще използваме само няколко.

Ако сте готови да тествате кода си, качете го в Arduino и натиснете [Shift] + [Ctrl] + [M], за да отворите серийния монитор и да видите дали получавате някакъв изход. Ако получавате данни от Arduino, ние сме готови да преминем към C# частта от кода …

Стъпка 3: Създайте C# проект

За да покажа нашата графика, първоначално започнах проект в Processing, но по -късно реших, че ще бъде твърде бавно да показваме всички обекти, които трябва да покажем. Затова избрах да използвам C#, който се оказа много по -плавен и по -отзивчив при обработката на нашия вход.

За C# частта от проекта е най -добре просто да изтеглите.zip файла и да го извлечете в собствената му папка, след което да го промените. В zip файла има две папки. За да отворите проекта във Visual Studio, въведете папката RunnerGame_CSharp в Windows Explorer. Тук щракнете двукратно върху файла.sln (решение) и VS ще зареди проекта.

Създадох няколко различни класа за играта. Няма да навлизам във всички подробности за всеки клас, но ще дам преглед на това за какво са основните класове.

Класът на кутията

Създадох класа box, за да ви позволя да създавате прости правоъгълни обекти, които могат да бъдат нарисувани на екрана под формата на windows. Идеята е да се създаде клас, който може да бъде разширен, като се използват други класове, които може да искат да нарисуват някакъв вид графики. Ключовата дума „виртуален“се използва, така че други класове да ги заменят (използвайки ключовата дума „надменят“). По този начин можем да получим същото поведение за класа Player и Platform, когато е необходимо, и също така да променяме обектите, колкото е необходимо.

Не се притеснявайте прекалено много за всички имоти и теглете обаждания. Написах този клас, за да мога да го разширя за всяка игра или графична програма, която бих искал да направя в бъдеще. Ако трябва просто да нарисувате правоъгълник в движение, не е нужно да изписвате голям клас като този. Документацията на C# има добри примери за това как да направите това.

Ще изложа обаче част от логиката на моя клас "Box":

публичен виртуален бул IsCollidedX (Box otherObject) {…}

Тук проверяваме за сблъсъци с обекти в X-посока, защото играчът трябва само да провери за сблъсъци в посока Y (нагоре и надолу), ако е подравнен с него на екрана.

публичен виртуален bool IsCollidedY (Box otherObject) {…}

Когато сме над или под друг обект на игра, проверяваме за Y сблъсъци.

публичен виртуален bool IsCollided (Box otherObject) {…}

Това комбинира сблъсъци X и Y, връщайки дали някой обект е сблъсък с този.

публична виртуална празнота OnPaint (графични графики) {…}

Използвайки горния метод, ние предаваме всеки графичен обект и го използваме, докато програмата работи. Ние създаваме правоъгълници, които може да се наложи да бъдат нарисувани. Това обаче може да се използва за различни анимации. За нашите цели правоъгълниците ще се справят както на платформите, така и на плейъра.

Класът на знаците

Класът Character разширява моя клас Box, така че имаме известна физика извън кутията. Създадох метода „CheckForCollisions“, за да проверя бързо всички създадени от нас платформи за сблъсък. Методът "Jump" задава възходящата скорост на играча към променливата JumpSpeed, която след това се променя кадър по кадър в класа MainWindow.

Тук сблъсъците се обработват малко по -различно, отколкото в класа Box. В тази игра реших, че ако скочим нагоре, можем да прескочим през платформа, но тя ще хване играча ни по пътя надолу, ако се сблъска с нея.

Класът на платформата

В тази игра използвам само конструктора на този клас, който приема X-координата като вход, изчислявайки всички X позиции на платформите в класа MainWindow. Всяка платформа е настроена на произволна Y-координата от 1/2 на екрана до 3/4 от височината на екрана. Височината, ширината и цветът също се генерират на случаен принцип.

Класът MainWindow

Тук поставяме цялата логика, която да се използва, докато играта работи. Първо, в конструктора отпечатваме всички COM портове, достъпни за програмата.

foreach (низ от порт в SerialPort. GetPortNames ())

Console. WriteLine ("НАЛИЧНИ ПОРТОВЕ:" + порт);

Ние избираме на кой да приемаме комуникации, според кой порт вашият Arduino вече използва:

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

Обърнете специално внимание на командата: SerialPort. GetPortNames () [2]. [2] означава кой сериен порт да се използва. Например, ако програмата отпечата „COM1, COM2, COM3“, щяхме да слушаме COM3, защото номерирането започва с 0 в масива.

Също така в конструктора създаваме всички платформи с полуслучайни разстояния и поставяне в посока Y на екрана. Всички платформи са добавени към обект List, който в C# е просто много лесен за използване и ефективен начин за управление на структура от данни, подобна на масив. След това създаваме Player, който е нашият Character обект, задаваме резултата на 0 и задаваме GameOver на false.

частна статична празнота DataReceived (изпращач на обект, SerialDataReceivedEventArgs e)

Това е методът, който се извиква при получаване на данни на серийния порт. Тук ние прилагаме цялата си физика, решаваме дали да покажем играта, да преместваме платформите и т.н. освежава. В тази игра методът DataReceived действа като контур на играта, като само манипулира физиката, тъй като данните се получават от контролера. Може би щеше да е по -добре да настроите таймер в главния прозорец и да опресните обектите въз основа на получените данни, но тъй като това е проект на Arduino, исках да направя игра, която всъщност да се изпълнява въз основа на данните, идващи от него.

В заключение, тази настройка дава добра основа за разширяване на играта в нещо използваемо. Въпреки че физиката не е съвсем перфектна, тя работи достатъчно добре за нашите цели, а именно да използваме Arduino за нещо, което всеки харесва: играене на игри!

Препоръчано: