Оглавление:

Платформер, управляемый Arduino, с джойстиком и ИК-приемником: 3 шага (с изображениями)
Платформер, управляемый Arduino, с джойстиком и ИК-приемником: 3 шага (с изображениями)

Видео: Платформер, управляемый Arduino, с джойстиком и ИК-приемником: 3 шага (с изображениями)

Видео: Платформер, управляемый Arduino, с джойстиком и ИК-приемником: 3 шага (с изображениями)
Видео: Arduino машинка своими руками. Управление с помощью джойстика 2024, Декабрь
Anonim
Платформер, управляемый Arduino, с джойстиком и ИК-приемником
Платформер, управляемый Arduino, с джойстиком и ИК-приемником

Сегодня мы собираемся использовать микроконтроллер Arduino для управления простой платформерной игрой на C #. Я использую Arduino для приема входных данных от модуля джойстика и отправки этих входных данных в приложение C #, которое прослушивает и декодирует входные данные через последовательное соединение. Хотя для завершения проекта вам не нужен какой-либо предыдущий опыт создания видеоигр, может потребоваться некоторое время, чтобы понять некоторые вещи, происходящие в «игровом цикле», который мы обсудим позже.

Для выполнения этого проекта вам понадобятся:

  • Сообщество Visual Studio
  • Arduino Uno (или аналогичный)
  • Модуль контроллера джойстика
  • Терпение

Если вы готовы начать, продолжайте!

Шаг 1. Подключите джойстик и ИК-светодиод

Подключите джойстик и ИК-светодиод
Подключите джойстик и ИК-светодиод
Подключите джойстик и ИК-светодиод
Подключите джойстик и ИК-светодиод

Здесь подключение довольно простое. Я включил диаграммы, показывающие только подключенный джойстик, а также используемую мной установку, которая включает в себя джойстик и инфракрасный светодиод для управления игрой с помощью пульта дистанционного управления, который поставляется со многими наборами Arduino. Это необязательно, но возможность играть в беспроводные игры показалась хорошей идеей.

В установке используются следующие выводы:

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

Шаг 2: Создайте новый эскиз

Создать новый эскиз
Создать новый эскиз

Мы начнем с создания нашего файла эскиза Arduino. Это опрашивает джойстик на предмет изменений и отправляет эти изменения программе C # каждые несколько миллисекунд. В реальной видеоигре мы проверяли бы последовательный порт в игровом цикле на вход, но я начал игру как эксперимент, поэтому частота кадров фактически основана на количестве событий на последовательном порту. На самом деле я начал этот проект в родственном проекте Arduino, Processing, но оказалось, что он был намного медленнее и не мог обрабатывать количество ящиков на экране.

Итак, сначала создайте новый Sketch в программе редактора кода Arduino. Я покажу свой код, а затем объясню, что он делает:

#include "IRremote.h"

// ИК-переменные int Receiver = 3; // Сигнальный контакт ИК-приемника IRrecv irrecv (приемник); // создать экземпляр irrecv decode_results results; // создать экземпляр decode_results // джойстик / игровые переменные int xPos = 507; int yPos = 507; байт joyXPin = A0; байт joyYPin = A1; byte joySwitch = 2; изменчивый байт clickCounter = -1; int minMoveHigh = 530; int minMoveLow = 490; int currentSpeed = 550; // По умолчанию = средняя скорость int speedIncrement = 25; // Количество увеличения / уменьшения скорости с Y input unsigned long current = 0; // Сохраняет текущую временную метку int wait = 40; // мс для ожидания между сообщениями [Примечание: более низкое ожидание = более высокая частота кадров] volatile bool buttonPressed = false; // Проверить, нажата ли кнопка void setup () {Serial.begin (9600); pinMode (joySwitch, INPUT_PULLUP); attachInterrupt (0, прыжок, ПАДЕНИЕ); ток = миллис (); // Установить текущее время // Настроить инфракрасный приемник: irrecv.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 ((Строка) xPos + "," + (Строка) yPos + ',' + (Строка) currentSpeed + '\ n'); ток = миллис (); }} // loop int getSpeed (int yPos) {// Отрицательные значения указывают на то, что джойстик перемещен вверх if (yPos 1023? 1023: currentSpeed + speedIncrement;} else if (yPos> minMoveHigh) // Интерпретация "Вниз" {// Защита от переход под 0 return currentSpeed - speedIncrement <0? 0: currentSpeed - speedIncrement;}} // getSpeed void jump () {buttonPressed = true; // Указывает, что кнопка была нажата.} // прыжок // При нажатии кнопки на удаленный, обработать правильный ответ void translateIR (decode_results results) // предпринимает действия на основе полученного IR-кода {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: // Последовательный. println ("6"); xPos = 900; break; case 0xFF4AB5: //Serial.println("8 "); currentSpeed - = speedIncrement * 2; break; default: //Serial.println (" другая кнопка "); break;} // Конечный переключатель} // КОНЕЦ translateIR

Я попытался создать код, который в основном не требует пояснений, но есть несколько моментов, о которых стоит упомянуть. Одна вещь, которую я пытался объяснить, заключалась в следующих строках:

int minYMoveUp = 520;

int minYMoveDown = 500;

Когда программа работает, аналоговый вход от джойстика имеет тенденцию «прыгать», обычно оставаясь на отметке 507. Чтобы исправить это, вход не изменяется, если он не больше minYMoveUp или меньше minYMoveDown.

pinMode (joySwitch, INPUT_PULLUP);

attachInterrupt (0, прыжок, ПАДЕНИЕ);

Метод 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. Здесь дважды щелкните файл.sln (решение), и VS загрузит проект.

Я создал для игры несколько разных классов. Я не буду вдаваться в подробности о каждом классе, но дам обзор того, для чего предназначены основные классы.

Класс Box

Я создал класс box, чтобы вы могли создавать простые прямоугольные объекты, которые можно рисовать на экране в форме окна. Идея состоит в том, чтобы создать класс, который можно расширить с помощью других классов, которые могут захотеть нарисовать какую-то графику. Ключевое слово virtual используется для того, чтобы другие классы могли их переопределить (используя ключевое слово override). Таким образом, мы можем получить одинаковое поведение для класса Player и класса Platform, когда нам нужно, а также изменить объекты, как нам нужно.

Не беспокойтесь слишком обо всех свойствах и вызовах отрисовки. Я написал этот класс, чтобы можно было расширить его для любой игры или графической программы, которую я, возможно, захочу создать в будущем. Если вам нужно просто нарисовать прямоугольник на лету, вам не нужно писать такой большой класс. В документации C # есть хорошие примеры того, как это сделать.

Однако я изложу часть логики моего класса "Box":

public virtual bool IsCollidedX (Box otherObject) {…}

Здесь мы проверяем наличие столкновений с объектами в направлении X, потому что игроку нужно проверять наличие столкновений только в направлении Y (вверх и вниз), если он выровнен с ним на экране.

public virtual bool IsCollidedY (Box otherObject) {…}

Когда мы находимся над или под другим игровым объектом, мы проверяем наличие Y столкновений.

public virtual bool IsCollided (Box otherObject) {…}

Это объединяет столкновения X и Y, возвращая, столкнулся ли какой-либо объект с этим.

public virtual void 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.

private static void DataReceived (отправитель объекта, SerialDataReceivedEventArgs e)

Это метод, который вызывается при получении данных через последовательный порт. Здесь мы применяем всю нашу физику, решаем, отображать ли игру, перемещать платформы и т. Д. Если вы когда-либо создавали игру, у вас обычно есть так называемый «игровой цикл», который вызывается каждый раз, когда кадр освежает. В этой игре метод DataReceived действует как игровой цикл, управляя физикой только по мере получения данных от контроллера. Возможно, было бы лучше настроить таймер в главном окне и обновлять объекты на основе полученных данных, но поскольку это проект Arduino, я хотел создать игру, которая действительно запускалась на основе данных, поступающих от него..

В заключение, эта установка дает хорошую основу для расширения игры до чего-то полезного. Хотя физика не совсем идеальна, она работает достаточно хорошо для наших целей, а именно для использования Arduino для чего-то, что нравится всем: для игр!

Рекомендуемые: