아두이노와 도트매트릭스를 활용하여 테트리스 게임을 제작해봅시다.
아래 영상을 참고하여 만들었습니다.
주요 부품
훈민정음 게임기를 만들 때도 사용되었던 도트 매트릭스를 활용합니다.
도트 매트릭스

도트 매트릭스란? 도트 매트릭스는 LED(발광 다이오드)로 이루어진 격자 형태의 디스플레이 장치입니다. 각 LED는 개별적으로 켜고 끌 수 있어 다양한 문자나 이미지를 표현할 수 있습니다. 도트 매트릭스는 보통 8×8, 16×16 등의 크기로 제공되며, 여러 개를 결합하여 더 큰 디스플레이를 만들 수도 있습니다.
아두이노에서 도트 매트릭스 사용하기 아두이노를 사용하여 도트 매트릭스를 제어할 수 있습니다. 이를 통해 다양한 애니메이션, 텍스트 스크롤링, 심볼 등을 디스플레이할 수 있습니다. 일반적으로 MAX7219 또는 HT16K33와 같은 드라이버 칩을 사용하여 도트 매트릭스를 제어합니다.
주요 구성 요소와 용도
1. 도트 매트릭스 디스플레이
- 설명: LED로 구성된 격자형 디스플레이로, 각 LED를 개별적으로 제어하여 다양한 그래픽을 표현할 수 있습니다.
- 용도: 텍스트 스크롤링, 간단한 애니메이션, 시간 및 온도 표시 등.
2. MAX7219 드라이버 칩
- 설명: 도트 매트릭스 디스플레이를 제어하기 위한 칩으로, 다수의 LED를 간편하게 제어할 수 있도록 도와줍니다.
- 용도: 아두이노와 도트 매트릭스 사이의 인터페이스 역할을 하여, 코드 작성과 회로 구성을 간편하게 만듭니다.
LCD 16×2 (I2C 제어) 디스플레이 모듈

아두이노 LCD 16×2 디스플레이 모듈은 16개의 문자(열)와 2개의 행으로 구성된 Liquid Crystal Display(침수형 액정 디스플레이)입니다. I2C (Inter-Integrated Circuit) 제어 방식은 두 개의 데이터 라인(SDA, SCL)을 통해 여러 장치와 통신할 수 있어, Wiring이 간단하고 코드도 명료하게 작성할 수 있습니다.
사용법
- 연결: I2C 모듈을 아두이노에 연결합니다. SDA는 아두이노의 A4 핀에, SCL은 A5 핀에 연결합니다. VCC는 5V에, GND는 GND에 연결합니다.
- 라이브러리 설치: 아두이노 IDE에서
LiquidCrystal_I2C
라이브러리를 설치합니다.- 아두이노 IDE -> 스케치 -> 라이브러리 포함 -> 라이브러리 관리에서 “LiquidCrystal I2C”를 검색하여 설치합니다.
택트 스위치

택트 스위치는 전기 회로 내에서 버튼 역할을 하는 작은 스위치입니다. 누르면 회로가 연결되고, 떼면 회로가 끊어지는 방식으로 작동합니다. 구현이 간단하며 디지털 입력을 받기 위해 주로 사용됩니다.
부저

부저는 소리를 발생시키는 전자기기입니다. 종종 상황에 따라 비프음이나 경고음을 만들기 위해 사용됩니다. 아두이노와 함께 사용하여 다양한 소리를 낼 수 있습니다.
회로도

핀 연결은 아래와 같습니다.
아두이노 | 도트 매트릭스 |
5V | VCC |
GND | GND |
D12 | DIN |
D10 | CS |
D11 | CLK |
아두이노 | LCD |
GND | GND |
5V | VCC |
A4 | SDA |
A5 | SCL |
아두이노 | 스위치 |
D6 | START |
D5 | RIGHT |
D4 | DOWN |
D3 | LEFT |
D2 | ROTATION |
아두이노 | 부저 |
GND | GND |
D7 | VCC |
하드웨어 제작/조립 방법
사진 업데이트 예정
코드
아두이노에서 아래 코드를 업로드 해줍니다. 제공된 소스코드에서 점수와 레벨을 표시하도록 LCD를 추가 연결하면서 일부 수정을 하였습니다.
보드는 아두이노 나노 보드를 사용하는데 업로드 과정에서 오류가 생긴다면 프로세서에서 Old Bootloader를 선택해줍니다.

#include <LedControl.h> #include <Wire.h> #include <LiquidCrystal_I2C.h> // LCD 설정: I2C 주소 0x27, 화면 크기 16x2 LiquidCrystal_I2C lcd(0x27, 16, 2); LedControl lc = LedControl(12, 11, 10, 2); // (dataPin, clockPin, csPin, totalDevices) int lc0[] = {0, 0, 0, 0, 0, 0, 0, 0}; int lc1[] = {0, 0, 0, 0, 0, 0, 0, 0}; long active[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; long screen[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int tmpCol = 0; int figura = 0; int figuraNext = 0; int fromLeft = 0; int fromRight = 0; int angle = 0; int colCheck = 0; int moveCheck = 0; int score = 0; int started = 0; int lcRows = 16; int lcCols = 8; int allLines = 0; int currLines = 0; int brickDelay = 0; int defDelay = 500; int level = 0; boolean sound = true; //Pinos int rotate_button = 2; int left_button = 3; int down_button = 4; int right_button = 5; int start_button = 6; int speaker_pin = 7; int sound_button = 8; byte X[8] = { 0b00000, 0b10001, 0b01010, 0b00100, 0b01010, 0b10001, 0b00000, 0b00000 }; byte O[8] = { 0b00000, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b00000, 0b00000 }; byte L[8] = { 0b11000, 0b11000, 0b11000, 0b11000, 0b11000, 0b11111, 0b11111, 0b00000 }; byte J[8] = { 0b00011, 0b00011, 0b00011, 0b00011, 0b00011, 0b11111, 0b11111, 0b00000 }; byte T[8] = { 0b00000, 0b00000, 0b11111, 0b11111, 0b01110, 0b01110, 0b00000, 0b00000 }; byte I[8] = { 0b01100, 0b01100, 0b01100, 0b01100, 0b01100, 0b01100, 0b01100, 0b00000 }; byte Z[8] = { 0b00000, 0b00000, 0b11110, 0b11110, 0b01111, 0b01111, 0b00000, 0b00000 }; byte S[8] = { 0b00000, 0b00000, 0b01111, 0b01111, 0b11110, 0b11110, 0b00000, 0b00000 }; //Nuty int length = 99; char notes[] = "EbCDCbaaCEDCbbCDECaa DFAGFEECEDCbbCDECaa EbCDCbaaCEDCbbCDECaa DFAGFEECEDCbbCDECaa ECDbCab ECDbCEAJ "; int beats[] = // Som { 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 2, 2, 2, 4, 2, 2, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 2, 2, 2, 4, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 2, 2, 2, 4, 2, 2, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 2, 2, 2, 4, 1, 5, 5, 5, 5, 5, 5, 7, 2, 5, 5, 5, 5, 2, 2, 5, 5, 3 }; int tempo = 128; // Tempo void playTone(int tone, int duration) { for (long i = 0; i < duration * 1000L; i += tone * 2) { digitalWrite(speaker_pin, HIGH); delayMicroseconds(tone); digitalWrite(speaker_pin, LOW); delayMicroseconds(tone); } } void playNote(char note, int duration) { char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C' , 'D', 'E', 'F', 'G', 'J', 'A', 'B'}; int tones[] = { 1915, 1700, 1519, 1432, 1275, 1136, 1014, 956, 850, 760, 716, 637, 603, 568, 507 }; for (int i = 0; i < 14; i++) { if (names[i] == note) { playTone(tones[i], duration); } } } void updateColumn(int colnum) { lc0[colnum] = active[colnum] >> (lcRows / 2); lc1[colnum] = active[colnum]; lc.setColumn(0,colnum,(screen[colnum] >> (lcRows / 2)) | lc0[colnum]); lc.setColumn(1,colnum,screen[colnum] | lc1[colnum]); } void buttonDelay(int bdelay) { if(brickDelay > bdelay) { brickDelay -= bdelay; } delay(bdelay); } void splashScreen() { int up[] = { B11101110, // o o o o o o B01001000, // o o B01001100, // o o o B01001000, // o o B01001110, // o o o o B00000000, // B11101110, // o o o o o o B01001010 // o o o }; int down[] = { B01001100, // o o o B01001010, // o o o B01001001, // o o o B00000000, // B01000111, // o o o o B01000100, // o o B01000010, // o o B01001110 // o o o o }; for(int rownum = 0; rownum < 8; rownum++) { lc.setRow(0,rownum,up[rownum]); lc.setRow(1,rownum,down[rownum]); } } void setup() { pinMode(speaker_pin, OUTPUT); pinMode(rotate_button,INPUT_PULLUP); pinMode(down_button, INPUT_PULLUP); pinMode(right_button, INPUT_PULLUP); pinMode(left_button, INPUT_PULLUP); pinMode(start_button, INPUT_PULLUP); pinMode(sound_button, INPUT_PULLUP); lc.shutdown(0,false); lc.shutdown(1,false); lc.setIntensity(0,5); lc.setIntensity(1,5); lc.clearDisplay(0); lc.clearDisplay(1); Serial.begin(9600); lcd.begin(16, 2); // LCD 초기화 lcd.backlight(); // LCD 백라이트 켬 lcd.clear(); lcd.setCursor(0, 0); lcd.print("Welcome to Game!"); delay(2000); // 2초 대기 randomSeed(analogRead(0)); } void loop(){ if(started == 0) { splashScreen(); for (int i = 0; i < length; i++) { if(digitalRead(sound_button) == LOW) { sound =! sound; delay(300); } if(digitalRead(start_button) == LOW) { lcd.clear(); lcd.setCursor(0, 0); lcd.print("Game Start!"); delay(1000); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Game Level : "); lcd.setCursor(0, 1); lcd.print("Your Score : 0"); started = 1; break; } if (notes[i] == ' ') { delay(beats[i] * tempo); //Pausa } else { if (sound == 1){ playNote(notes[i], beats[i] * tempo); } else { digitalWrite(speaker_pin,LOW); } } delay(tempo / 2); } } else { lc.clearDisplay(0); lc.clearDisplay(1); memset(lc0, 0, sizeof(lc0)); memset(lc1, 0, sizeof(lc1)); memset(active, 0, sizeof(active)); memset(screen, 0, sizeof(screen)); tmpCol = 0; while(started == 1) { if(allLines < 100) { level = 1; //Level 0 lcd.setCursor(13, 0); lcd.print(level); } else if(allLines < 200) { level = 2; //Level 1 lcd.setCursor(13, 0); lcd.print(level); } else if(allLines < 300) { level = 3; //Level 2 lcd.setCursor(13, 0); lcd.print(level); } else if(allLines < 400) { level = 4; //Level 3 lcd.setCursor(13, 0); lcd.print(level); } else if(allLines < 500) { level = 5; //Level 4 lcd.setCursor(13, 0); lcd.print(level); } else { level = 6; //Level 5 lcd.setCursor(13, 0); lcd.print(level); } defDelay = (5 - level) * 100; brickDelay = defDelay; if(figura == 0) { figura = random(1,8); } else { figura = figuraNext; } figuraNext = random(1,8); angle = 0; switch(figura) { case 1: //"O" active[3] = 131072 + 65536; active[4] = 131072 + 65536; fromLeft = 3; fromRight = 3; break; case 2: //"L" active[3] = 262144 + 131072 + 65536; active[4] = 65536; fromLeft = 3; fromRight = 3; break; case 3: //"J" active[3] = 65536; active[4] = 262144 + 131072 + 65536; fromLeft = 3; fromRight = 3; break; case 4: //"T" active[2] = 131072; active[3] = 131072 + 65536; active[4] = 131072; fromLeft = 2; fromRight = 3; break; case 5: //"I" active[3] = 524288 + 262144 + 131072 + 65536; fromLeft = 3; fromRight = 4; break; case 6: //"Z" active[2] = 131072; active[3] = 131072 + 65536; active[4] = 65536; fromLeft = 2; fromRight = 3; break; case 7: //"S" active[2] = 65536; active[3] = 131072 + 65536; active[4] = 131072; fromLeft = 2; fromRight = 3; break; } for(int krok = 0; krok < lcRows + 1; krok++) { colCheck = 0; for(int i = 0; i < (lcCols / 2); i++) { if((digitalRead(left_button) == LOW) && (fromLeft > 0)) { moveCheck = 0; for(int colnum = fromLeft; colnum < (lcCols - fromRight); colnum++) { if((active[colnum] & screen[colnum - 1]) == 0) { moveCheck++; } } if(moveCheck == (lcCols - fromLeft - fromRight)) { for(int colnum = (fromLeft - 1); colnum < (lcCols - fromRight); colnum++) { if(colnum < (lcCols - 1)) { active[colnum] = active[colnum+1]; } else { active[colnum] = 0; } updateColumn(colnum); } fromLeft--; fromRight++; playNote('E', 10); buttonDelay(200); } } } for(int i = 0; i < (lcCols / 2); i++) { if((digitalRead(right_button) == LOW) && (fromRight > 0)) { moveCheck = 0; for(int colnum = fromLeft; colnum < (lcCols - fromRight); colnum++) { if((active[colnum] & screen[colnum + 1]) == 0) { moveCheck++; } } if(moveCheck == (lcCols - fromLeft - fromRight)) { for(int colnum = (lcCols - fromRight); colnum > (fromLeft - 1); colnum--) { if(colnum > 0) { active[colnum] = active[colnum-1]; } else { active[colnum] = 0; } updateColumn(colnum); } fromLeft++; fromRight--; playNote('E', 10); buttonDelay(200); } } } if(digitalRead(down_button) == LOW) { brickDelay = 0; playNote('b', 10); } else { brickDelay = defDelay; } for(int i = 0; i < (lcCols / 2); i++) { if(digitalRead(rotate_button) == LOW) { switch(figura) { case 1: //"O" break; case 2: //"L" switch(angle) { case 0: // . o . . . . // . o . ---> o o o // . o o o . . if((fromLeft > 0) && (((active[fromLeft + 1] | (active[fromLeft + 1] << 1)) & screen[fromLeft - 1]) == 0)) { active[fromLeft - 1] = (active[fromLeft + 1] | (active[fromLeft + 1] << 1)); updateColumn(fromLeft - 1); active[fromLeft] = (active[fromLeft + 1] << 1); updateColumn(fromLeft); active[fromLeft + 1] = (active[fromLeft + 1] << 1); updateColumn(fromLeft + 1); fromLeft--; angle = 1; } break; case 1: // . . . o o . // o o o ---> . o . // o . . . o . if((((active[fromLeft + 2] << 1) & screen[fromLeft]) == 0) && ((((active[fromLeft + 1] << 1) | (active[fromLeft + 1] >> 1)) & screen[fromLeft + 1]) == 0)) { active[fromLeft] = (active[fromLeft + 2] << 1); updateColumn(fromLeft); active[fromLeft + 1] = active[fromLeft + 1] | (active[fromLeft + 1] << 1) | (active[fromLeft + 1] >> 1); updateColumn(fromLeft + 1); active[fromLeft + 2] = 0; updateColumn(fromLeft + 2); fromRight++; angle = 2; } break; case 2: // o o . . . o // . o . ---> o o o // . o . . . . if((fromRight > 0) && (((active[fromLeft] >> 1) & screen[fromLeft]) == 0) && ((((active[fromLeft + 1] << 1) & active[fromLeft + 1]) & screen[fromLeft + 1]) == 0)) { active[fromLeft] = (active[fromLeft] >> 1); updateColumn(fromLeft); active[fromLeft + 1] = active[fromLeft]; updateColumn(fromLeft + 1); active[fromLeft + 2] = ((active[fromLeft + 1] << 1) | active[fromLeft + 1]); updateColumn(fromLeft + 2); fromRight--; krok--; angle = 3; } break; case 3: // . . o . o . // o o o ---> . o . // . . . . o o if(((((active[fromLeft] << 1) | (active[fromLeft] >> 1)) & screen[fromLeft + 1]) == 0) && (((active[fromLeft] >> 1) & screen[fromLeft + 2]) == 0) && (krok < lcRows)) { active[fromLeft] = 0; updateColumn(fromLeft); active[fromLeft + 1] = (active[fromLeft + 2] | (active[fromLeft + 2] >> 1)); updateColumn(fromLeft + 1); active[fromLeft + 2] = ((active[fromLeft + 2] >> 1) & (active[fromLeft + 2] >> 2)); updateColumn(fromLeft + 2); fromLeft++; krok++; angle = 0; } break; } break; case 3: //"J" switch(angle) { case 0: // . o . o . . // . o . ---> o o o // o o . . . . if((fromRight > 0) && ((((active[fromLeft] << 2) | (active[fromLeft] << 1)) & screen[fromLeft]) == 0) && (((active[fromLeft] << 1) & screen[fromLeft + 2]) == 0)) { active[fromLeft] = ((active[fromLeft] << 2) | (active[fromLeft] << 1)); updateColumn(fromLeft); active[fromLeft + 1] = ((active[fromLeft + 1] << 1) & (active[fromLeft + 1] >> 1)); updateColumn(fromLeft + 1); active[fromLeft + 2] = active[fromLeft + 1]; updateColumn(fromLeft + 2); fromRight--; krok--; angle = 1; } break; case 1: // o . . . o o // o o o ---> . o . // . . . . o . if((krok < lcRows) && ((((active[fromLeft + 1] << 1) | (active[fromLeft + 1] >> 1)) & screen[fromLeft + 1]) == 0) && (((active[fromLeft + 2] << 1) & screen[fromLeft + 2]) == 0)) { active[fromLeft] = 0; updateColumn(fromLeft); active[fromLeft + 1] = (active[fromLeft + 1] | (active[fromLeft + 1] << 1) | (active[fromLeft + 1] >> 1)); updateColumn(fromLeft + 1); active[fromLeft + 2] = (active[fromLeft + 2] << 1); updateColumn(fromLeft + 2); fromLeft++; krok++; angle = 2; } break; case 2: // . o o . . . // . o . ---> o o o // . o . . . o if((fromLeft > 0) && (((active[fromLeft + 1] >> 1) & screen[fromLeft - 1]) == 0) && ((((active[fromLeft + 1] >> 1) | (active[fromLeft + 1] >> 2)) & screen[fromLeft + 1]) == 0)) { active[fromLeft - 1] = (active[fromLeft + 1] >> 1); updateColumn(fromLeft - 1); active[fromLeft] = active[fromLeft - 1]; updateColumn(fromLeft); active[fromLeft + 1] = (active[fromLeft] | (active[fromLeft + 1] >> 2)); updateColumn(fromLeft + 1); fromLeft--; angle = 3; } break; case 3: // . . . . o . // o o o ---> . o . // . . o o o . if((((active[fromLeft] >> 1) & screen[fromLeft]) == 0) && ((((active[fromLeft] << 1) | (active[fromLeft >> 1])) & screen[fromLeft + 1]) == 0)) { active[fromLeft] = (active[fromLeft] >> 1); updateColumn(fromLeft); active[fromLeft + 1] = ((active[fromLeft + 1] << 1) | active[fromLeft + 2]); updateColumn(fromLeft + 1); active[fromLeft + 2] = 0; updateColumn(fromLeft + 2); fromRight++; angle = 0; } break; } break; case 4: //"T" switch(angle) { case 0: // . . . . o . // o o o ---> o o . // . o . . o . if(((active[fromLeft + 1] << 1) & screen[fromLeft + 1]) == 0) { //active[fromLeft] active[fromLeft + 1] = active[fromLeft + 1] | (active[fromLeft + 1] << 1); updateColumn(fromLeft + 1); active[fromLeft + 2] = 0; updateColumn(fromLeft + 2); fromRight++; angle = 1; } break; case 1: // . o . . o . // o o . ---> o o o // . o . . . . if((fromRight > 0) && ((active[fromLeft] & screen[fromLeft + 2])== 0)) { //active[fromLeft] active[fromLeft + 1] = active[fromLeft + 1] & (active[fromLeft + 1] << 1); updateColumn(fromLeft + 1); active[fromLeft + 2] = active[fromLeft]; updateColumn(fromLeft + 2); fromRight--; krok--; angle = 2; } break; case 2: // . o . . o . // o o o ---> . o o // . . . . o . if((((active[fromLeft + 1] >> 1) & screen[fromLeft + 1]) == 0) && (krok < lcRows)) { active[fromLeft] = 0; updateColumn(fromLeft); active[fromLeft + 1] = active[fromLeft + 1] | (active[fromLeft + 1] >> 1); updateColumn(fromLeft + 1); //active[fromLeft + 2] fromLeft++; krok++; angle = 3; } break; case 3: if((fromLeft > 0) && ((active[fromLeft + 1] & screen[fromLeft - 1]) == 0)) { active[fromLeft - 1] = active[fromLeft + 1]; updateColumn(fromLeft - 1); active[fromLeft] = active[fromLeft] & (active[fromLeft] >> 1); updateColumn(fromLeft); fromLeft--; angle = 0; } break; } break; case 5: //"I" switch(angle) { case 0: // . o . . . . . . // . o . . ---> o o o o // . o . . . . . . // . o . . . . . . if((fromLeft > 0) && (fromRight > 1) && ((((((active[fromLeft] >> 1) & (active[fromLeft] << 2)) & screen[fromLeft - 1]) & screen[fromLeft + 1]) & screen[fromLeft + 2]) == 0)) { active[fromLeft - 1] = ((active[fromLeft] >> 1) & (active[fromLeft] << 2)); updateColumn(fromLeft - 1); active[fromLeft] = active[fromLeft - 1]; updateColumn(fromLeft); active[fromLeft + 1] = active[fromLeft]; updateColumn(fromLeft + 1); active[fromLeft + 2] = active[fromLeft]; updateColumn(fromLeft + 2); fromLeft--; fromRight -= 2; krok -= 2; angle = 1; } break; case 1: // . . . . . . o . // o o o o ---> . . o . // . . . . . . o . // . . . . . . o . if((krok < (lcRows - 1)) && (((active[fromLeft] << 1) | (active[fromLeft] >> 1) | (active[fromLeft] >> 2)) & screen[fromLeft + 2]) == 0) { active[fromLeft] = 0; updateColumn(fromLeft); active[fromLeft + 1] = 0; updateColumn(fromLeft + 1); active[fromLeft + 2] = (active[fromLeft + 2] | (active[fromLeft + 2] << 1) | (active[fromLeft + 2] >> 1) | (active[fromLeft + 2] >> 2)); updateColumn(fromLeft + 2); active[fromLeft + 3] = 0; updateColumn(fromLeft + 3); fromLeft += 2; fromRight++; krok += 2; angle = 2; } break; case 2: // . . o . . . . . // . . o . ---> . . . . // . . o . o o o o // . . o . . . . . if((fromLeft > 1) && (fromRight > 0) && ((((((active[fromLeft] << 1) & (active[fromLeft] >> 2)) & screen[fromLeft - 2]) & screen[fromLeft - 1]) & screen[fromLeft + 1]) == 0)) { active[fromLeft - 2] = ((active[fromLeft] << 1) & (active[fromLeft] >> 2)); updateColumn(fromLeft - 2); active[fromLeft - 1] = active[fromLeft - 2]; updateColumn(fromLeft - 1); active[fromLeft] = active[fromLeft - 1]; updateColumn(fromLeft); active[fromLeft + 1] = active[fromLeft]; updateColumn(fromLeft + 1); fromLeft -= 2; fromRight--; krok--; angle = 3; } break; case 3: // . . . . . o . . // . . . . ---> . o . . // o o o o . o . . // . . . . . o . . if((krok < (lcRows)) && (((active[fromLeft] >> 1) | (active[fromLeft] << 1) | (active[fromLeft] << 2)) & screen[fromLeft + 1]) == 0) { active[fromLeft] = 0; updateColumn(fromLeft); active[fromLeft + 1] = (active[fromLeft + 1] | (active[fromLeft + 1] >> 1) | (active[fromLeft + 1] << 1) | (active[fromLeft + 1] << 2)); updateColumn(fromLeft + 1); active[fromLeft + 2] = 0; updateColumn(fromLeft + 2); active[fromLeft + 3] = 0; updateColumn(fromLeft + 3); fromLeft++; fromRight += 2; krok++; angle = 0; } break; } break; case 6: //"Z" switch(angle) { case 0: // . . . . o . // o o . ---> o o . // . o o o . . if(((active[fromLeft + 1] & screen[fromLeft]) == 0) && (((active[fromLeft + 1] << 1) & screen[fromLeft + 1]) == 0)) { active[fromLeft] = active[fromLeft + 1]; updateColumn(fromLeft); active[fromLeft + 1] = (active[fromLeft + 1] << 1); updateColumn(fromLeft + 1); active[fromLeft + 2] = 0; updateColumn(fromLeft + 2); fromRight++; angle = 1; } break; case 1: // . o . o o . // o o . ---> . o o // o . . . . . if((fromRight > 0) && ((((active[fromLeft] << 2) & (active[fromLeft] << 1)) & screen[fromLeft]) == 0) && (((active[fromLeft] & active[fromLeft + 1]) & screen[fromLeft + 2]) == 0)) { active[fromLeft] = ((active[fromLeft] << 2) & (active[fromLeft] << 1)); updateColumn(fromLeft); //active[fromLeft + 1] active[fromLeft + 2] = (active[fromLeft] >> 1); updateColumn(fromLeft + 2); fromRight--; krok--; angle = 2; } break; case 2: // o o . . . o // . o o ---> . o o // . . . . o . if((krok < lcRows) && (((active[fromLeft + 1] >> 1) & screen[fromLeft + 1]) == 0) && (((active[fromLeft + 2] << 1) & screen[fromLeft + 2]) == 0)) { active[fromLeft] = 0; updateColumn(fromLeft); active[fromLeft + 1] = (active[fromLeft + 1] >> 1); updateColumn(fromLeft + 1); active[fromLeft + 2] = (active[fromLeft + 2] | (active[fromLeft + 2] << 1)); updateColumn(fromLeft + 2); fromLeft++; krok++; angle = 3; } break; case 3: // . . o . . . // . o o ---> o o . // . o . . o o if((fromLeft > 0) && (((active[fromLeft] & active[fromLeft + 1]) & screen[fromLeft - 1]) == 0) && (((active[fromLeft + 1] >> 1) & screen[fromLeft + 1]) == 0)) { active[fromLeft - 1] = (active[fromLeft] & active[fromLeft + 1]); updateColumn(fromLeft - 1); //active[fromLeft] active[fromLeft + 1] = (active[fromLeft - 1] >> 1); updateColumn(fromLeft + 1); fromLeft--; angle = 0; } break; } break; case 7: //"S" switch(angle) { case 0: // . . . o . . // . o o ---> o o . // o o . . o . if(((active[fromLeft + 1] << 1) & screen[fromLeft]) == 0) { active[fromLeft] = (active[fromLeft + 1] << 1); updateColumn(fromLeft); //active[fromLeft + 1] active[fromLeft + 2] = 0; updateColumn(fromLeft + 2); fromRight++; angle = 1; } break; case 1: // o . . . o o // o o . ---> o o . // . o . . . . if((fromRight > 0) && (((active[fromLeft + 1] << 1) & screen[fromLeft + 1]) == 0) && (((active[fromLeft] & (active[fromLeft] << 1)) & screen[fromLeft + 2]) == 0)) { active[fromLeft] = (active[fromLeft] & active[fromLeft + 1]); updateColumn(fromLeft); active[fromLeft + 1] = (active[fromLeft + 1] << 1); updateColumn(fromLeft + 1); active[fromLeft + 2] = (active[fromLeft] << 1); updateColumn(fromLeft + 2); fromRight--; krok--; angle = 2; } break; case 2: // . o o . o . // o o . ---> . o o // . . . . . o if((krok < lcRows) && (((active[fromLeft + 1] >> 1) & screen[fromLeft + 2]) == 0)) { active[fromLeft] = 0; updateColumn(fromLeft); //active[fromLeft + 1] active[fromLeft + 2] = (active[fromLeft + 1] >> 1); updateColumn(fromLeft + 2); fromLeft++; krok++; angle = 3; } break; case 3: // . o . . . . // . o o ---> . o o // . . o o o . if((fromLeft > 0) && ((active[fromLeft + 1] & ((active[fromLeft + 1] >> 1)) & screen[fromLeft - 1]) == 0) && ((active[fromLeft + 1] & screen[fromLeft]) == 0)) { active[fromLeft - 1] = (active[fromLeft + 1] & (active[fromLeft + 1] >> 1)); updateColumn(fromLeft - 1); active[fromLeft] = active[fromLeft + 1]; updateColumn(fromLeft); active[fromLeft + 1] = (active[fromLeft - 1] << 1); updateColumn(fromLeft + 1); fromLeft--; angle = 0; } break; } break; } playNote('E', 10); buttonDelay(200); } } //Restart if(digitalRead(start_button) == LOW) { memset(lc0, 0, sizeof(lc0)); memset(lc1, 0, sizeof(lc1)); memset(active, 0, sizeof(active)); memset(screen, 0, sizeof(screen)); score = 0; allLines = 0; // lcd.setCursor(13, 1); // lcd.print(allLines); figura = 0; break; } for(int colnum = 0; colnum < lcCols; colnum++) { if((screen[colnum] & (active[colnum] >> 1)) == 0) { colCheck++; } else { colCheck = 0; if(krok == 0) { started = 0; } } } if((colCheck == lcCols) && (krok < lcRows)) { for(int colnum = 0; colnum < lcCols; colnum++) { active[colnum] = active[colnum] >> 1; updateColumn(colnum); } } else { break; } delay(brickDelay); } for(int colnum = 0; colnum < lcCols; colnum++) { screen[colnum] = screen[colnum] | (lc0[colnum] << (lcRows / 2)); screen[colnum] = screen[colnum] | lc1[colnum]; lc0[colnum] = 0; lc1[colnum] = 0; active[colnum] = 0; } currLines = 0; for(int rownum = 0; rownum < lcRows; rownum++) { colCheck = 0; for(int colnum = 0; colnum < lcCols; colnum++) { if(((screen[colnum] >> rownum) & 1) == 1) { colCheck++; } } if(colCheck == lcCols) { //Animacja kasowania for(int colnum = 0; colnum < lcCols; colnum++) { tmpCol = ~((int) round(pow(2, rownum))); screen[colnum] = screen[colnum] & tmpCol; updateColumn(colnum); switch(currLines) { case 0: playNote('b', 20); break; case 1: playNote('D', 20); break; case 2: playNote('F', 20); break; case 3: playNote('A', 20); break; } delay(30); tmpCol = (int) (round(pow(2, rownum)) - 1); tmpCol = screen[colnum] & tmpCol; screen[colnum] = (screen[colnum] >> (rownum + 1)); screen[colnum] = (screen[colnum] << rownum); screen[colnum] = screen[colnum] | tmpCol; } for(int colnum = 0; colnum < lcCols; colnum++) { updateColumn(colnum); } rownum--; currLines++; allLines++; String score = String(allLines); lcd.setCursor(13, 1); lcd.print(score); } } if(currLines > 0) { score += (int) round(pow(4, currLines-1)); } } gameOver(); // == Game Over == } } void gameOver() { playNote('F', 80); playNote('A', 60); playNote('F', 80); playNote('A', 60); int cima[] = { B11111111, // o o o o o o o o B11111111, // o o o o o o o o B11111111, // o o o o o o o o B11111111, // o o o o o o o o B11111111, // o o o o o o o o B11111111, // o o o o o o o o B11111111, // o o o o o o o o B11111111 // o o o o o o o o }; int baixo[] = { B11111111, // o o o o o o o o B11111111, // o o o o o o o o B11111111, // o o o o o o o o B11111111, // o o o o o o o o B11111111, // o o o o o o o o B11111111, // o o o o o o o o B11111111, // o o o o o o o o B11111111 // o o o o o o o o }; for(int rownum = 8; rownum >= 0; rownum--) { lc.setRow(1,rownum,baixo[rownum]); delay(100); } for(int rownum = 8; rownum >= 0; rownum--) { lc.setRow(0,rownum,cima[rownum]); delay(100); } delay(1800); }