Реклама ⓘ
Главная » Arduino
Призовой фонд
на апрель 2024 г.
1. 100 руб.
От пользователей

Похожие статьи:


Реклама ⓘ

Игровая ТВ-приставка на Arduino. Часть 2

Приступим к созданию игры с условным названием "Арифметический сборщик". Игрок управляется джойстиком с возможностью перемещения по полю размером 128x90. При нулевых отклонениях джойстика игрок находится в центре. Максимальное отклонение джойстика соответствует максимальному перемещению игрока. С определенным интервалом времени генерируются объекты-цифры, которые движутся сверху вниз. По достижении нижнего положения экрана объект-цифра исчезает, уменьшая количество баллов игрока на величину данной цифры. Если игрок перехватывает объект-цифру на экране, то это приводит к исчезновению объекта-цифры и увеличению счетчика баллов игрока. С определенной периодичностью значок игрока меняет свое значение с цифры 0 до 9. При перехвате объекта-цифры счетчик баллов игрока увеличивается на сумму, равную сумме объекта-цифры и цифры игрока, если цифра игрока равняется цифре объекта-цифры, то счетчик баллов игрока увеличивается на произведение цифр. По достижении определенных порогов баллов, происходит переход на более высокий уровень игры, что приводит к увеличению скорости движения и скорости генерации объектов-цифр. Кроме того с 4 уровня игры столкновение игрока с объектом-цифрой приводит не только к увеличению счетчика игрока, но и уменьшению (если цифра игрока меньше цифры объекта-цифры). Если количество баллов игрока становится меньше 0, игра начинается сначала.

Вот видео того, что получилось

Скачать архив со скетчем и файлами библиотеки TVOut можно по ссылке

И сам процесс создания игры

Создание переменных игры

Для управления игрой создадим объекты для хранения текущего положения игры. Символ, отображающий игрока, и символы, отображающие объекты-цифры, выводятся как текстовая информация, поэтому поделим все поле игры на строки и все перемещения объектов будем производить как вывод символа в знакоместо на поле. Переменные MAX_X=31 и MAX_Y=14 определяют размер поля игры по количеству знакомест по горизонтали и вертикали. Переменная MAX_OBJ=30 определяет максимальное количество одновременно находящихся на поле игры объектов-цифр. Массив int FIGURA[30][3] хранит информации об объектах-цифрах, находящихся на поле игры следующим образом:

  • FIGURA[i][0]  – числовое значение объекта-цифры (0 – пустой объект);
  • FIGURA[i][1] – текущая координата x объекта-цифры;
  • FIGURA[i][2] – текущая координата y объекта-цифры.

Для хранения прочих переменных, описывающих текущее состояние игры, создадим структуру GAME. Список полей структуры:

  • xk – координата x(/4) игрока;
  • yk – координата y(/6) игрока;
  • tekCursor – текущее значение курсора;
  • blinkCursor – текущее состояние блинка курсора;
  • vblink – скорость blink в vk ;
  • vk – скорость движения игрока - проверка входов A0,A1;
  • vo_10 – скорость изменения цифры игрока;
  • vo_11 – скорость появления объектов-цифр;
  • vo_12 – скорость движения объектов-цифр;
  • count_objects – кол-во объектов-цифр на поле;
  • level – уровень игры;
  • balls – кол-во баллов.
int MAX_X=31;
int MAX_Y=14;
// структура данных игры
struct GAME // структура для данных игры
{
 int xk;   // координата x(/4) игрока
 int yk;   // координата y(/6) игрока
 int tekCursor; // текущее значение курсора
 int blinkCursor; // текущее состояние блинка курсора
 int vblink; // скорость blink в vk
 long vk;   // скорость движения игрока - проверка входов A0,A1
 long vo_10;   // скорость изменения цифры игрока
 long vo_11;   // скорость появления цифр
 long vo_12;   // скорость движения цифр
 int count_objects; //кол-во объектов на поле
 int level;   // уровень игры 
 int balls;   // кол-во баллов
};

int MAX_OBJ=30;
int FIGURA[30][3]={{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},
   {0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},
   {0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},
   {0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},
   {0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},
   {0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}
   };

Управления положением игрока с помощью джойстика.

Положение игрока на экране определяется отклонением джойстика. Выводы джойстика подключены к аналоговым портам A0, A1 платы Arduino. Опрос портов происходит через время, определенное параметром GAME.vk, эти данные  обрабатываются функцией map(), которая пропорционально переносит значение из текущего диапазона 0-124 в новый диапазон (значения ширины и высоты экрана). Затем это значение переводится в координаты знакоместа. В это знакоместо необходимо переместить изображение символа игрока, предварительно поместив в предыдущее положение игрока символ пробела. Для отображения игрока используется мигающий символ – цифра и пробел. 

//****************** установка нового положения игрока
void set_iam()
 {
 TV.set_cursor(min(123,GAME1.xk*4),min(84,GAME1.yk*6));
 TV.print(" ");
 GAME1.xk=map(analogRead(A0), 0, 1024, 0, 128);
 GAME1.yk=map(analogRead(A1), 0, 1024, 0, 96);
 GAME1.xk=GAME1.xk/4;
 GAME1.yk=GAME1.yk/6;
 GAME1.vblink--;
   if(GAME1.vblink<0)
   {
   GAME1.blinkCursor=1-GAME1.blinkCursor;
   GAME1.vblink=5+GAME1.blinkCursor*5;
   }
 TV.set_cursor(min(123,GAME1.xk*4),min(84,GAME1.yk*6));
 if(GAME1.blinkCursor==1) 
   TV.print(GAME1.tekCursor);
 else 
   TV.print(" ");   
 }

Символ, отображающий игрока меняется через время, определенное параметром GAME.vo_10, вызовом функции set_new_cursor(), изменение происходит случайным образом с помощью функции random(). 

//****************** установка нового вида символа игрока
void set_new_cursor()
 {
 GAME1.tekCursor=random(0,10);
 }

Генерация и перемещение объектов-цифр.

Объекты-цифры генерируются через время, определенное параметром GAME.vo11. Вызывается функция set_new_object(). Информация обо всех объектах-цифрах хранится в массиве FIGURA[30][3]. Программа ищет первый пустой индекс в массиве (FIGURA[30][3]=0), и помещает в него новый объект-цифру.  Цифровое значение и горизонтальная координата нового объекта генерируются функцией random, а вертикальная координата устанавливается равной нулю. Символ, отображающий новый объект-цифру, выводится на экран. 

//****************** появление нового объекта-цифры
void set_new_object()
 {
 int null_index=0;
 if(GAME1.count_objects)<>
   {
   for(int i=0;i;i++)<>
   {
   if(FIGURA[i][0]==0)
     {null_index=i;break;}
   }
   FIGURA[null_index][0]=random(1,9);
   FIGURA[null_index][1]=random(0,MAX_X);
   FIGURA[null_index][2]=0;
   // вывод на доску
   TV.set_cursor(FIGURA[null_index][1]*4,0);
   TV.print(FIGURA[null_index][0]);   
   GAME1.count_objects++;
   }
 }

Функция движении объектов-цифр (go_object()) вызывается через время, определенное параметром GAME.vo12. Визуализация движения объектов-цифр происходит путем стирания символа из предыдущего положения объекта(запись символа пробела), и записью символа объекта в новое положение (вертикальная координата знакоместа объекта-цифры увеличивается на единицу). По достижении низа экрана происходит удаление объекта-цифры (запись 0 в элемент массива FIGURA[i][0]), а также уменьшение количества баллов игрока. 

//****************** движение объекта-цифры
void go_object()
 {
 for(int i=0;i;i++)<>
  {
   if(FIGURA[i][0]>0)
   {
   TV.set_cursor(FIGURA[i][1]*4,FIGURA[i][2]*6);
   TV.print(" ");   
   if(FIGURA[i][2])<>
    {
    FIGURA[i][2]++;
    TV.set_cursor(FIGURA[i][1]*4,FIGURA[i][2]*6);
    TV.print(FIGURA[i][0]);
    }
   else
    {
    TV.tone(294,200);
    change_balls(FIGURA[i][0]*(-1));
    FIGURA[i][0]=0;
    GAME1.count_objects--;
    }
   }
  }
 }

Проверка столкновения игрока и объектов-цифр.

При перемещении символа игрока по экрану необходимо проверять столкновения игрока с объектами-цифрами. Для этого используем функцию collision(). После установки символа, соответствующего игроку, проверяем элементы массива FIGURA на соответствие координат объектов-цифр координатам символа игрока. При совпадении координат выполняем следующие действия:

  • уничтожается объект-цифра из массива FIGURA (запись 0 в FIGURA[[i][0]);
  • уменьшается на 1 счетчик количества объектов-цифр (GAME.count_objects)
  • производится изменение счетчика количества баллов игрока (вызов функции change_balls()).
//****************** проверка столкновения
void collision()
 {
 for(int i=0;i;i++)<>
   {
   if(FIGURA[i][0]>0)
     {
     if(FIGURA[i][1]==GAME1.xk && FIGURA[i][2]==GAME1.yk)
       {
       TV.tone(740,200);
       if(FIGURA[i][0]==GAME1.tekCursor)
         change_balls(GAME1.tekCursor*GAME1.tekCursor);
       else if(FIGURA[i][0]>GAME1.tekCursor && GAME1.level>3)
         change_balls(FIGURA[i][0]*(-1));
       else
         change_balls(FIGURA[i][0]+GAME1.tekCursor);   
       FIGURA[i][0]=0;
       GAME1.count_objects--;
       }
     }
   }
 }

В функцию изменение счетчика количества баллов игрока (change_balls()) в качестве аргумента передается число, на которое следует увеличить (уменьшить) счетчик баллов игрока. Это число равно сумме объекта-цифры и цифры игрока. Если цифра игрока равняется цифре объекта-цифры, то передается значение, равное произведению цифр. Для повышения сложности игры с 4 уровня столкновение игрока с объектом-цифрой приводит не только к увеличению счетчика игрока, но и уменьшению (если цифра игрока меньше цифры объекта-цифры).

Счетчик баллов игрока.

Функция change_balls() производит изменение счетчика баллов игрока на величину входящего аргумента. Если счетчик количества баллов становится меньше 0, игра заканчивается, экран очищается и происходит перехов на начало игры. Кроме того, при достижении счетчиком определенных значений, происходит переход игры на новый, более высокий, уровень. Установку значений для нового уровня выполняет функция new_level(). 

//****************** изменение набранных балов
void change_balls(int ball)
 {
 GAME1.balls=GAME1.balls+ball;
 if(GAME1.balls<0)
   start_game();
 if(GAME1.balls>(GAME1.level+1)*100)
   new_level(GAME1.level);
 set_data_tablo(); 
 }

Переход на новый уровень.

При переходе на новый уровень игры происходит установка новых значений для скорости генерации и скорости перемещения объектов-цифр. Первоначально предполагалось менять и значение скорости изменения цифры игрока, скорости движения игрока, но в ходе испытания игры решил от этого отказаться. Действия установки значений переменных для нового уровня игры производятся в функции new_level()
 

//****************** изменение уровня игры
void new_level(int tek_level)
 {
 GAME1.level++;
 GAME1.vo_10=5000;
 GAME1.vo_11=2000-(GAME1.level-1)*100; 
 GAME1.vo_12=1000-(GAME1.level-1)*100;   
 }

Отображение данных игры на табло.

Табло с данными игрока находится внизу экрана. Здесь отображается текущие значения количество набранных баллов и уровень игры. При изменении счетчика баллов игрока происходит вызов функции set_data_tablo(), которое изменяет значение количества набранных баллов и уровень игры в переменных структуры GAME и на табло.
 

//****************** вывод данных на табло
void set_data_tablo()
 {
 TV.print(20,91," balls=   ");
 TV.print(70,91," level=   ");
 TV.print(48,91,GAME1.balls);
 TV.print(98,91,GAME1.level);
 }

Звуковое сопровождение игры.

Для звукового оформления игры будем использовать функцию tone(frequency, duration) библиотеки TVOut. При достижении объектом-цифрой низа игрового поля – TV.tone(294,200) (функция go_object()), при столкновении игрока и объекта-цифры – TV.tone(740,200) (функция collision()). Если вы захотите в проект вставить фрагмент из последовательного воспроизведения нескольких нот, после вывода каждой ноты командой tone(frequency, duration) нобходимо вставлять командой delay() задержку длительностью не меньшей, чем параметр duration,6 – последовательное воспроизведении е двух но с паузой.

TV.tone(294,200);
TV.delay(400);
TV.tone(740,200);

Основной цикл игры.

Основной цикл программы состоит из вызова рассмотренных нами функций set_iam(), collision(), go_object(), set_new_object(), set_new_cursor() через промежуток времени установленный в переменных GAME.vk, GAME.vo_10, GAME.vo_11, GAME.vo_12. 

int game1()
 {
 while(GAME1.balls>0 && GAME1.level<6)
   { 
   long time2=millis();
   if(time2-time11>GAME1.vk)
     {set_iam();
     collision();
     time11=time2;
     }
   if(time2-time12>GAME1.vo_12)
     {go_object();time12=time2;}
   if(time2-time13>GAME1.vo_11)
     {set_new_object();time13=time2;}
   if(time2-time14>GAME1.vo_10)
     {set_new_cursor();time14=time2;}
   TV.delay_frame(10); 
   }
 if(GAME1.balls<0)
   return 0;
 else if(GAME1.level>5)
   return 0;
 else
   return 1;   
 }

Добавляем меню для выбора игр.

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

void loop() {
   switch(menu(pmenu))
   {
   case 1:start_game();
   while(game1()>0);
   break;
   default:
   break;
   }
 }

//***** меню для выбора игры
int menu(int poz)
 {
   TV.clear_screen();
   pmenu=max(poz,1);
   int pmenu1=pmenu;
   TV.println(60,30,"Game 1");
   TV.println(60,50,"Game 2");
   TV.println(60,70,"Game 3");
   TV.draw_rect(50,5+20*pmenu,40,10,WHITE,INVERT);
   TV.delay(500);
   while(digitalRead(12)==LOW)
   {
   if(analogRead(A1)<100)
     pmenu=max(pmenu-1,1);
   else if(analogRead(A1)>900)
     pmenu=min(pmenu+1,3);
   else 
     ;
   if(pmenu1!=pmenu)
    {
    TV.delay(500);
    TV.draw_rect(50,5+20*pmenu1,40,10,BLACK,INVERT);
    TV.draw_rect(50,5+20*pmenu,40,10,WHITE,INVERT);
    pmenu1=pmenu;
    }
   }
   return pmenu; 
 }

Теги:

Опубликована: 03.02.2013 0 0
Я собрал 0 4
x

Оценить статью

  • Техническая грамотность
  • Актуальность материала
  • Изложение материала
  • Полезность устройства
  • Повторяемость устройства
  • Орфография
0

Средний балл статьи: 4.3 Проголосовало: 4 чел.

Комментарии (2) | Я собрал (0) | Подписаться

0
shoma #
Захватывающая игра, а данный контроллер способен цветное изображение выводить?
Ответить
0

[Автор]
victoruni #
К сожалению, нет. Arduino не потянет вывод цветного изображения
Ответить
Добавить комментарий
Имя:
E-mail:
не публикуется
Текст:
Защита от спама:
В чем измеряется электрическое сопротивление?
Файлы:
 
Для выбора нескольких файлов использйте CTRL

Arduino UNO
Arduino UNO
Модуль радиореле на 4 канала Автомобильный GPS-трекер с GSM/GPRS и дистанционным управлением
вверх