Игра в змейку (Snake Game) стала очень популярной с момента появления мобильных телефонов. Сначала она появилась на мобильных телефонах с черно-белым экраном и ее популярность вскоре после этого стала стремительно расти. Вышло очень много версий данной игры для мобильных устройств различных форматов.
Также игра в змейку стала очень популярной самоделкой для энтузиастов в электронике. В этой статье мы рассмотрим реализацию данной игры с помощью платы Arduino Uno и светодиодной матрицы 8х8.
Необходимые компоненты
- Плата Arduino Uno (купить на AliExpress).
- ЖК дисплей 16х2 (купить на AliExpress).
- Переменный резистор (потенциометр) 1 кОм (купить на AliExpress).
- Светодиодная матрица 8x8 (точечный дисплей матричного типа) (купить на AliExpress).
- Регистр сдвига 74HC595 (купить на AliExpress).
- Кнопки.
- Макетная плата.
- Соединительные провода.
- Источник питания с напряжением 5 В.
Реклама: ООО "АЛИБАБА.КОМ (РУ)" ИНН: 7703380158
Общие принципы построения устройства для игры в змейку
Игра в змейку не является простой игрой в плане ее создания. Но в этой статье мы постарались сделать так, чтобы ее изготовление для вас стало достаточно простым делом. Для отображения игры мы использовали точечный дисплей матричного типа 8х8 красного цвета (со светодиодами красного цвета). ЖК дисплей будет использоваться для отображения счета игры. Кнопки будут использоваться для начала игры и задания направления движения змейки. Плата Arduino Uno будет управлять всем процессом. Схема расположения контактов точечного дисплея матричного типа 8х8 представлена на следующем рисунке.
Когда мы будем подавать питание на схему на ЖК дисплее будет высвечиваться приветственная запись “Press Start To Play”. После этого в процессе игры ЖК дисплей будет отображать ее счет. На светодиодной матрице будет отображаться две точки, символизирующих змею (snake) и одна точка, символизирующая еду (food).
После этого пользователь должен будет нажать среднюю кнопку чтобы начать игру – по умолчанию змея начнет двигаться вверх. Затем пользователь сможет изменять направление движения змеи при помощи нажатия кнопок, расположенных вокруг кнопки начала игры – это будут кнопки движения влево, движения вправо, вверх и вниз. Всегда, когда змея достигает еды (светящейся точки, символизирующей ее), ее длина увеличивается на одну точку и она начинает двигаться быстрее чем раньше. При этом счет игры увеличивается на 5. А когда змея ударяется об стену (то есть достигает края светодиодной матрицы) игра заканчивается – и на ЖК дисплее высвечивается надпись “Game Over”. Чтобы начать игру заново необходимо нажать кнопку старта.
Структурная схема работы устройства приведена на следующем рисунке.
Работа схемы
Схема устройства представлена на следующем рисунке.
Для подключения светодиодной матрицы к плате Arduino Uno мы использовали регистры сдвига 74HC595 поскольку без них у нас на Arduino физически не хватит свободных контактов для подключения светодиодной матрицы. Один регистр сдвига будет управлять столбцами матрицы, а другой – строками. Регистры сдвига (их контакты управления) подключены к контактам Arduino 14 и 16. Контакты DS этих регистров подключены к контактам Arduino 15 и 17. Кнопки подключены к следующим контактам Arduino:
- старт – к контакту 3;
- кнопка движения влево – к контакту 4;
- кнопка движения вправо – к контакту 6;
- кнопка движения вверх – к контакту 2;
- кнопка движения вниз – к контакту 5.
ЖК дисплей подключен к Arduino в 4-битном режиме. Его контакты RS и EN непосредственно подсоединены к контактам 13 и 12 Arduino, а его контакты данных d4-d7 – к контактам 11, 10, 9, 8 Arduino.
Исходный код программы
Для написания программы по управлению змейкой на Arduino нам необходимо сначала подключить необходимые заголовочные файлы и инициализировать контакты, которые нам понадобятся.
#include<LiquidCrystal.h>
LiquidCrystal lcd(13,12,11,10,9,8);
#define ds_col 15
#define sh_col 16
#define st_col 14
#define ds_row 17
#define start 3
#define up 2
#define down 5
#define left 4
#define right 6
Затем необходимо инициализировать ЖК дисплей, задать направление работы для используемых контактов и показать приветственное сообщение на ЖК дисплее.
void setup()
{
lcd.begin(16,2);
pinMode(ds_col, OUTPUT);
pinMode(sh_col, OUTPUT);
pinMode(st_col, OUTPUT);
pinMode(ds_row, OUTPUT);
pinMode(start, INPUT);
... ....
.... ....
После этого в функции loop мы начнем игру.
void show_snake(int temp)
{
for(int n=0;n<temp;n++)
{
int r,c;
for(int k=0;k<21;k++)
{
... ....
.... ....
В программе мы будем использовать следующие функции для считывания направления движения змейки от кнопок.
void read_button()
{
if(!digitalRead(left))
{
move_r=0;
move_c!=-1 ? move_c=-1 : move_c=1;
while(!digitalRead(left));
... ....
.... ....
Далее представлен полный текст программы.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
#include<LiquidCrystal.h> LiquidCrystal lcd(13,12,11,10,9,8); #define ds_col 15 #define sh_col 16 #define st_col 14 #define ds_row 17 #define start 3 #define up 2 #define down 5 #define left 4 #define right 6 char Col[21],Row[21],move_c,move_r; int colum_data(int temp) { switch(temp) { case 1: return 1;break; case 2: return 2; break; case 3: return 4; break; case 4: return 8; break; case 5: return 16; break; case 6: return 32; break; case 7: return 64; break; case 8: return 128; break; default: return 0; break; } } int row_data(int temp) { switch(temp) { case 1: return 1;break; case 2: return 2; break; case 3: return 4; break; case 4: return 8; break; case 5: return 16; break; case 6: return 32; break; case 7: return 64; break; case 8: return 128; break; default: return 0; break; } } void read_button() { if(!digitalRead(left)) { move_r=0; move_c!=-1 ? move_c=-1 : move_c=1; while(!digitalRead(left)); } if(!digitalRead(right)) { move_r=0; move_c!=1 ? move_c=1 : move_c=-1; while(!digitalRead(right)); } if(!digitalRead(up)) { move_c=0; move_r!=-1 ? move_r=-1 : move_r=1; while(!digitalRead(up)); } if(!digitalRead(down)) { move_c=0; move_r!=1 ? move_r=1 : move_r=-1; while(!digitalRead(down)); } } void show_snake(int temp) { for(int n=0;n<temp;n++) { int r,c; for(int k=0;k<21;k++) { int temp1=Col[k]; c=colum_data(temp1); int temp2=Row[k]; r=0xff-row_data(temp2); for(int i=0;i<8;i++) { int ds=(c & 0x01); digitalWrite(ds_col, ds); ds=(r & 0x01); digitalWrite(ds_row, ds); digitalWrite(sh_col, HIGH); c>>=1; r>>=1; digitalWrite(sh_col, LOW); } digitalWrite(st_col, HIGH); digitalWrite(st_col, LOW); read_button(); delayMicroseconds(500); } } } void setup() { lcd.begin(16,2); pinMode(ds_col, OUTPUT); pinMode(sh_col, OUTPUT); pinMode(st_col, OUTPUT); pinMode(ds_row, OUTPUT); pinMode(start, INPUT); pinMode(up, INPUT); pinMode(down, INPUT); pinMode(left, INPUT); pinMode(right, INPUT); digitalWrite(up, HIGH); digitalWrite(down, HIGH); digitalWrite(left, HIGH); digitalWrite(right, HIGH); digitalWrite(start, HIGH); lcd.setCursor(0,0); lcd.print(" Snake game "); lcd.setCursor(0,1); lcd.print("Circuit Digest "); delay(2000); lcd.setCursor(0,0); lcd.print(" Press Start "); lcd.setCursor(0,1); lcd.print(" To Play "); delay(2000); } void loop() { int j,k,Speed=40,score=0; j=k=move_c=0; move_r=1; lcd.clear(); lcd.setCursor(0,0); lcd.print("Score: "); lcd.print(score); while(1) { for(int i=3;i<21;i++) { Row[i]=100; Col[i]=100; } Row[0]=rand()%8+1; Col[0]=rand()%8+1; Row[1]=1; Col[1]=1; Row[2]=2; Col[2]=1; j=2,k=1; while(k==1) { move_c=0; move_r=1; show_snake(1); lcd.setCursor(7,0); lcd.print(score); if(!digitalRead(start)) { k=2; Speed=40; score=0; } } while(k==2) { show_snake(Speed); if(Row[1]>8 || Col[1]>8 || Row[1]<0 || Col[1]<0) { Row[1]=1; Col[1]=1; k=1; lcd.setCursor(0,1); lcd.print("Game Over"); delay(5000); score=0; lcd.clear(); lcd.setCursor(0,0); lcd.print("Score: "); lcd.print(score); } if(Row[0]==Row[1]+move_r && Col[0]==Col[1]+move_c) { j++; Speed-=2; score=score+5; lcd.setCursor(7,0); lcd.print(score); Row[0]=rand()%8+1; Col[0]=rand()%8+1; } for(int i=j;i>1;i--) { Col[i]=Col[i-1]; Row[i]=Row[i-1]; } Col[1]=Col[2]+move_c; Row[1]=Row[2]+move_r; } } } |