Nazwa implementacji: Zróbmy grę - Tetris Autor: Łukasz Ciężki Opis implementacji: Implementacja zawiera sposób na stworzenie gry TETRIS obsługiwanej przez Arduino Kto z nas nie zna gry Tetris? Znając bibliotekę TVout zróbmy ją na Arduino. Uwaga: aby móc w nią zagrać należy posiadać Arduino z co najmniej 2kB RAM'u (np. UNO). Schemat połączeniowy (przyciski jako pull-up, czyli z podciąganiem do napięcia): Kod: #include <avr/io.h> #include <TVout.h> #include <fontall.h> #include "tetrislogo.h" TVout TV; #define szerokosc 116 #define wysokosc 106 #define gora 2 #define dol 3 #define lewo 4 #define prawo 5 #define funkcyjny 6 byte predkosc = 1; byte muzyka = 0; byte glosnosc = 5; boolean start = false; 1
boolean matrix[10][20]; byte pomocnik_szerokosci1 = 0.5 * szerokosc - 20; byte pomocnik_szerokosci2 = 0.5 * szerokosc + 20; byte odstep = 10; byte pozycjax = 4; byte pozycjay = 0; byte obecny = 0; byte nastepny = 0; byte obrot = 0; boolean prawa_strona = false; boolean kolizja = false; boolean kolizja_prawa = false; boolean kolizja_lewa = false; boolean nadmiar[3] = {0,0,0; byte mnoznik = 0; unsigned long punkty = 0; byte opadanie = 0; boolean blokada_obrotu = false; unsigned int linie = 0; unsigned int dwojki = 0; unsigned int trojki = 0; byte tetrisy = 0; void ekran_startowy(){ TV.bitmap(0,0,tetrislogo); digitalwrite(8,low); digitalwrite(10,high); digitalwrite(12,high); digitalwrite(13,high); while(1){ if((!digitalread(lewo)) (!digitalread(prawo)) (!digitalread(dol)) (!digitalread(gora))) return void(); void wybor_menu(byte &wybor, boolean kontynuacja){ while(1){ if(kontynuacja){ switch(wybor){ if((!digitalread(lewo)) && muzyka > 0) muzyka--; if((!digitalread(prawo)) && muzyka < 7) muzyka++; if(!digitalread(funkcyjny)){ start = true; return void(); default: else{ 2
switch(wybor){ if((!digitalread(lewo)) && predkosc > 1) predkosc--; if((!digitalread(prawo)) && predkosc < 10) predkosc++; if((!digitalread(lewo)) && muzyka > 0) muzyka--; if((!digitalread(prawo)) && muzyka < 7) muzyka++; if(!digitalread(funkcyjny)){ start = true; return void(); default: if((!digitalread(gora) && wybor > 0)) wybor--; if((!digitalread(dol) && wybor < 2)) wybor++; void koniec_gry(){ TV.select_font(font8x8ext); TV.draw_rect(0.3 * szerokosc - 4, 0.24 * wysokosc, 0.47 * szerokosc, 0.29 * wysokosc, 1, 0); TV.printPGM(0.5 * szerokosc - 24, 0.3 * wysokosc, PSTR("KONIEC")); TV.printPGM(0.5 * szerokosc - 24, 0.4 * wysokosc, PSTR(" GRY ")); while(1){ if((!digitalread(lewo)) (!digitalread(prawo)) (!digitalread(dol)) (!digitalread(gora)) (!digitalread(funkcyjny) void graj_muzyke(byte numer){ switch(numer){ digitalwrite(8,high); digitalwrite(10,low); digitalwrite(12,low); digitalwrite(13,low); digitalwrite(8,high); digitalwrite(10,low); digitalwrite(12,low); digitalwrite(13,high); digitalwrite(8,high); digitalwrite(10,low); digitalwrite(12,high); digitalwrite(13,low); 3
digitalwrite(8,high); digitalwrite(10,low); digitalwrite(12,high); digitalwrite(13,high); case 4: digitalwrite(8,high); digitalwrite(10,high); digitalwrite(12,low); digitalwrite(13,low); case 5: digitalwrite(8,high); digitalwrite(10,high); digitalwrite(12,low); digitalwrite(13,high); case 6: digitalwrite(8,high); digitalwrite(10,high); digitalwrite(12,high); digitalwrite(13,low); case 7: digitalwrite(8,high); digitalwrite(10,high); digitalwrite(12,high); digitalwrite(13,high); default: void menu(){ start = false; byte wybor = 0; //0 - wybór prędkości, 1 - wybór muzyki, 2 - wybor głośności, 3 - start byte *wsk_wybor = &wybor; boolean zmiana = false; TV.select_font(font8x8ext); while(1){ zmiana = false; if((!digitalread(lewo)) (!digitalread(prawo)) (!digitalread(dol)) (!digitalread(gora))) zmiana = true; wybor_menu(*wsk_wybor,false); if(zmiana){ TV.clear_screen(); TV.printPGM(9,5,PSTR("T E T R I S")); TV.printPGM(5,30,PSTR("Predkosc")); TV.set_cursor(5,40); for(byte i = 0; i < predkosc; i++) TV.print("*"); TV.printPGM(5,50,PSTR("Muzyka")); TV.set_cursor(5,60); switch(muzyka){ TV.print("-- Cisza --"); 4
TV.print("Korobeiniki"); TV.print("Bradinsky"); TV.print("Kalinka"); case 4: TV.print("Smuglianka"); case 5: TV.print("PoliuszkaPole"); case 6: TV.print("Na drodze"); case 7: TV.print("Bella Ciao"); default: TV.printPGM(18,96,PSTR("S T A R T")); switch(wybor){ TV.draw_rect(0,29,szerokosc,20,2,2); TV.draw_rect(0,49,szerokosc,20,2,2); TV.draw_rect(0,95,szerokosc,10,2,2); graj_muzyke(muzyka); if(start){ TV.clear_screen(); return void(); TV.delay(200); void pauza(){ start = false; byte wybor = 0; //0 - wybór muzyki, 1 - wybor głośności, 2 - wznow byte *wsk_wybor = &wybor; boolean zmiana = false; TV.select_font(font8x8ext); while(1){ zmiana = false; 5
if((!digitalread(lewo)) (!digitalread(prawo)) (!digitalread(dol)) (!digitalread(gora))) zmiana = true; wybor_menu(*wsk_wybor,true); if(zmiana){ TV.clear_screen(); TV.printPGM(9,5,PSTR("PAUZA")); TV.printPGM(5,30,PSTR("Muzyka")); TV.set_cursor(5,40); switch(muzyka){ TV.print("-- Cisza --"); TV.print("Korobeiniki"); TV.print("Bradinsky"); TV.print("Kalinka"); case 4: TV.print("Smuglianka"); case 5: TV.print("PoliuszkaPole"); case 6: TV.print("Na drodze"); case 7: TV.print("Bella Ciao"); default: TV.printPGM(18,70,PSTR("W Z N O W")); switch(wybor){ TV.draw_rect(0,29,szerokosc,20,2,2); TV.draw_rect(0,69,szerokosc,10,2,2); graj_muzyke(muzyka); if(start){ TV.clear_screen(); ramka(); rysuj_matrix(); return void(); if(wybor == 2) wybor = 0; TV.delay(200); 6
//poszczególne tetromino void L(byte x, byte y, byte p){ byte ot = obrot; if(p == 4){ ot++; if(ot == 4) ot = 0; switch(ot){ blok(x,y+2,p); blok(x+1,y+2,p); blok(x+2,y,p); blok(x+2,y+1,p); blok(x+1,y+2,p); blok(x+2,y,p); void J(byte x, byte y, byte p){ byte ot = obrot; if(p == 4){ ot++; if(ot == 4) ot = 0; switch(ot){ blok(x+1,y+2,p); 7
blok(x,y+2,p); blok(x+2,y+1,p); blok(x,y+2,p); blok(x+2,y,p); blok(x+2,y+1,p); void S (byte x, byte y, byte p){ byte ot = obrot; if(p == 4){ ot++; if(ot == 4) ot = 0; switch(ot){ blok(x+2,y,p); blok(x+1,y+2,p); 8
blok(x+2,y,p); blok(x+1,y+2,p); void Z (byte x, byte y, byte p){ byte ot = obrot; if(p == 4){ ot++; if(ot == 4) ot = 0; switch(ot){ blok(x+2,y+1,p); blok(x,y+2,p); blok(x+2,y+1,p); blok(x,y+2,p); 9
void I (byte x, byte y, byte p){ byte ot = obrot; if(p == 4){ ot++; if(ot == 4) ot = 0; switch(ot){ blok(x,y+2,p); blok(x,y+3,p); if(x == 9) prawa_strona = true; blok(x+2,y,p); blok(x+3,y,p); if(x+3 == 9) prawa_strona = true; blok(x,y+2,p); blok(x,y+3,p); if(x == 9) prawa_strona = true; blok(x+2,y,p); blok(x+3,y,p); if(x+3 == 9) prawa_strona = true; void O (byte x, byte y, byte p){ byte ot = obrot; if(p == 4){ ot++; if(ot == 4) ot = 0; switch(ot){ default: 10
void T (byte x, byte y, byte p){ byte ot = obrot; if(p == 4){ ot++; if(ot == 4) ot = 0; switch(ot){ blok(x+2,y+1,p); blok(x,y+2,p); blok(x+2,y,p); blok(x+1,y+2,p); byte przesuniecie_wiersz = 0; void sprawdz_wiersze(){ byte w = 0; for(byte j = 0; j < 20; j++){ for(byte i = 0; i < 10; i++){ if(matrix[i][j]) w++; 11
if(w == 10){ for(byte i = 0; i < 10; i++){ pisz_matrix(i,j,false); mnoznik++; przesuniecie_wiersz = j; przesun_wiersze(); w = 0; switch(mnoznik){ punkty += 100; linie++; punkty += 250; dwojki++; punkty += 1000; trojki++; case 4: punkty += 4000; tetrisy++; mnoznik = 0; void przesun_wiersze(){ for(byte j = przesuniecie_wiersz; j > 0; j--){ for(byte i = 0; i < 10; i++){ matrix[i][j] = matrix[i][j-1]; void losuj_tetromino(){ obecny = random(0,7); void wstaw_tetromino(byte rozkaz){ switch(obecny){ L(pozycjax, pozycjay, rozkaz); J(pozycjax, pozycjay, rozkaz); S(pozycjax, pozycjay, rozkaz); Z(pozycjax, pozycjay, rozkaz); case 4: I(pozycjax, pozycjay, rozkaz); case 5: O(pozycjax, pozycjay, rozkaz); case 6: T(pozycjax, pozycjay, rozkaz); boolean sprawdz_kolizje(byte x, byte y){ if(y == 19) return true; if(matrix[x][y + 1]) return true; return false; boolean sprawdz_kolizje_prawa(byte x, byte y){ if(x == 9) return true; if(matrix[x+1][y]) return true; return false; 12
boolean sprawdz_kolizje_lewa(byte x, byte y){ if(x == 0) return true; if(matrix[x-1][y]) return true; return false; boolean sprawdz_kolizje_matrix(byte x, byte y){ if(matrix[x][y]) return true; return false; void ramka(){ TV.draw_column(pomocnik_szerokosci1-1, odstep, wysokosc - odstep + 4, 1); TV.draw_column(pomocnik_szerokosci2, odstep, wysokosc - odstep + 4, 1); TV.draw_row(wysokosc - odstep + 4, 0.5 * szerokosc - 21, 0.5 * szerokosc + 21, 1); void czysc_matrix(){ for(byte i = 0; i < 10; i++){ for (byte j = 0; j < 20; j++){ matrix[i][j] = false; void rysuj_matrix(){ TV.draw_rect(pomocnik_szerokosci1, odstep + 1, 39, pomocnik_szerokosci2 + odstep, 0, 0); for(byte i = 0; i < 10; i++){ for(byte j = 0; j < 20; j++){ if(matrix[i][j]) blok_matrix(i,j); void pisz_matrix(byte x, byte y, boolean typ){ matrix[x][y] = typ; void blok(byte x, byte y, byte w){ if(w == 4){ if(sprawdz_kolizje(x,y - 1)) blokada_obrotu = true; if(sprawdz_kolizje_matrix(x,y)) blokada_obrotu = true; if(x > 9) blokada_obrotu = true; if(w == 3){ //czyszczenie z ekranu poprzedniej pozycji bloku TV.draw_rect(x * 4 + pomocnik_szerokosci1, y * 4 + 2 * odstep, 3, 3, 0, 0); if(w == 2){ if(x == 10) nadmiar[0] = true; if(x == 11) nadmiar[1] = true; if(x == 12) nadmiar[2] = true; if(w == 1) matrix[x][y] = true; 13
if(w == 0){ TV.draw_rect(x * 4 + pomocnik_szerokosci1, y * 4 + 2 * odstep, 3, 3, 1, 1); kolizja = sprawdz_kolizje(x,y); kolizja_lewa = sprawdz_kolizje_lewa(x,y); kolizja_prawa = sprawdz_kolizje_prawa(x,y); void blok_matrix(byte x, byte y){ TV.draw_rect(x * 4 + pomocnik_szerokosci1, y * 4 + 2 * odstep, 3, 3, 1, 1); void steruj(){ if((!digitalread(lewo)) && pozycjax > 0 &&!kolizja_lewa) pozycjax--; if((!digitalread(prawo)) && pozycjax < 9 &&!kolizja_prawa) pozycjax++; if((!digitalread(gora))){ pauza(); TV.select_font(font4x6); if((!digitalread(dol)) && pozycjay < 19) pozycjay++; wstaw_tetromino(4); if((!digitalread(funkcyjny)) && obrot < 4 &&!blokada_obrotu){ obrot++; if(obrot == 4) obrot = 0; void gra(){ pozycjax = 4; pozycjay = 0; punkty = 0; linie = 0; dwojki = 0; trojki = 0; tetrisy = 0; TV.select_font(font4x6); TV.set_cursor(0,36); TV.print("Linie:"); TV.set_cursor(0,44); TV.print(linie, DEC); TV.set_cursor(0,54); TV.print("Dwojki:"); TV.set_cursor(0,60); TV.print(dwojki, DEC); TV.set_cursor(0,70); TV.print("Trojki:"); TV.set_cursor(0,78); TV.print(trojki, DEC); TV.set_cursor(0,88); TV.print("Tetris:"); TV.set_cursor(0,96); TV.print(tetrisy, DEC); kolizja = false; kolizja_prawa = false; kolizja_lewa = false; obecny = random(0,7); nastepny = random(0,7); TV.select_font(font4x6); czysc_matrix(); ramka(); nastepny = random(0,7); rysuj_matrix(); while(1){ 14
TV.set_cursor(0,30); if(kolizja && pozycjay == 0){ digitalwrite(8,low); digitalwrite(10,high); digitalwrite(12,high); digitalwrite(13,low); koniec_gry(); return void(); if(kolizja){ kolizja = false; punkty += 15; wstaw_tetromino(1); pozycjax = 4; pozycjay = 0; sprawdz_wiersze(); obecny = nastepny; nastepny = random(0,7); rysuj_matrix(); TV.set_cursor(0,36); TV.print("Linie:"); TV.set_cursor(0,44); TV.print(linie, DEC); TV.set_cursor(0,54); TV.print("Dwojki:"); TV.set_cursor(0,60); TV.print(dwojki, DEC); TV.set_cursor(0,70); TV.print("Trojki:"); TV.set_cursor(0,78); TV.print(trojki, DEC); TV.set_cursor(0,88); TV.print("Tetris:"); TV.set_cursor(0,96); TV.print(tetrisy, DEC); kolizja = false; wstaw_tetromino(3); //usun z ekranu tetromino wstaw_tetromino(4); //sprawdz mozliwą kolizje przy obrocie bloku steruj(); if(digitalread(dol)){ opadanie++; if(opadanie == 10 - predkosc){ opadanie = 0; pozycjay++; else{ punkty += predkosc; kolizja_lewa = false; kolizja_prawa = false; blokada_obrotu = false; //TV.set_cursor(0,0); TV.print(obecny,DEC); TV.print(" o"); //TV.set_cursor(0,10); TV.print(nastepny,DEC); TV.println(" n"); TV.set_cursor(0,10); TV.print("Punkty:"); TV.set_cursor(0,18); TV.print(punkty, DEC); wstaw_tetromino(0); TV.delay(100); 15
void setup(){ pinmode(8,output); pinmode(10,output); pinmode(12,output); pinmode(13,output); pinmode(gora,input_pullup); pinmode(dol,input_pullup); pinmode(lewo,input_pullup); pinmode(prawo,input_pullup); pinmode(funkcyjny,input_pullup); randomseed(analogread(0)); TV.begin(PAL,szerokosc,wysokosc); TV.select_font(font8x8); void loop(){ ekran_startowy(); TV.clear_screen(); menu(); TV.clear_screen(); gra(); Piny 8, 10, 12, 13 tworzą liczbę binarną, która jest przekazana do prostego odtwarzacza tonów (opartego na atmega8). Efekt: 16
17