You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
Play/play5/tetris.ino

652 lines
56 KiB

void tetris() {
randomSeed(analogRead(pinSeed)); random(12345); // Выбираем случайную точку входа в последовательность псевдослучайных чисел, для корректной работы функции random().
randomSeed(analogRead(pinSeed) + random(12345)); // Выбираем случайную точку входа в последовательность псевдослучайных чисел, для корректной работы функции random().
random(12345); // Вызываем функцию random() в холостую (т.к. её первое значение после функции randomSeed(...) часто повторяется).
figurePos[2] = (int8_t(tableCols) - 5) / 2; // Определяем начальный отступ новой фигуры слева (количество клеток от левого края игрового стола).
showWelcome(); // Выводим анимированное приветствие.
state = GAME_OFF; // Переводим состояние игры в GAME_OFF.
while (1)
{
but();
//*********** T O U C H ********************
if (myTouch.dataAvailable())
{
myTouch.read();
xt = myTouch.getX();
yt = myTouch.getY();
// Serial.print("xt=");
// Serial.println(xt);
// Serial.print("yt=");
// Serial.println(yt);
if ((xt >= 490) && (xt <= 550)) // Upper row
{
if ((yt >= 5) && (yt <= 50)) // Button: 1
{
valBtnPause = 1;
myGLCD.setColor(WHITE);
myGLCD.drawLine(503, 29, 503 + 60, 29);
myGLCD.drawLine(503, 30, 503 + 60, 30);
//myGLCD.drawLine(480, 45,480+60, 45);
}
if ((yt >= 220) && (yt <= 255)) // Button: 1
{
valBtnL = 1; //LEFT
myGLCD.setColor(WHITE);
myGLCD.drawLine(503, 239, 503 + 60, 239);
myGLCD.drawLine(503, 240, 503 + 60, 240);
}
}
if ((xt >= 560) && (xt <= 640)) // Upper row
{
if ((yt >= 110) && (yt <= 140)) // Button: 1
{
valBtnT = 1; //UP
myGLCD.setColor(WHITE);
myGLCD.drawLine(610, 132, 610 + 60, 132);
myGLCD.drawLine(610, 133, 610 + 60, 133);
}
if ((yt >= 320) && (yt <= 358)) // Button: 1
{
valBtnD = 1; //DOWN
myGLCD.setColor(WHITE);
myGLCD.drawLine(610, 344, 610 + 60, 344);
myGLCD.drawLine(610, 345, 610 + 60, 345);
}
}
if ((xt >= 700) && (xt <= 780)) // Upper row
{
if ((yt >= 220) && (yt <= 255)) // Button: 1
{
valBtnR = 1; //RIGHT
myGLCD.setColor(WHITE);
myGLCD.drawLine(713, 239, 713 + 60, 239);
myGLCD.drawLine(713, 240, 713 + 60, 240);
}
}
if ((xt >= 750) && (xt <= 790)) // Upper row
{
if ((yt >= 10) && (yt <= 60)) // Button: 1
{
exit_menu = 1; //ВЫХОД
}
}
}
delay(100);
//*************************************************************************************
if (exit_menu == 1)
{ exit_menu = 0;
loop();
}
//************ПАУЗА//*************************************************
if (valBtnPause == 1)
{ valBtnPause = 0;
myGLCD.setColor(RED);
// myGLCD.setBackColor (98,65,32);
myGLCD.setBackColor(VGA_TRANSPARENT);
// myGLCD.setColor(98,65,32);
myGLCD.print("P A U S E", 180, 100);
delay(500);
while (1)
{ //delay(500);
but();
if (myTouch.dataAvailable())
{
myTouch.read();
xt = myTouch.getX();
yt = myTouch.getY();
valBtnT = 1;
if ((xt >= 750) && (xt <= 790)) // Upper row
{
if ((yt >= 10) && (yt <= 60)) // Button: 1
{ valBtnT = 1;
exit_menu = 1; //ВЫХОД
}
}
}
if (valBtnL || valBtnR || valBtnT || valBtnD)
{ valBtnPause = 0;
valBtnT = 0;
myGLCD.setColor(99, 171, 243);
myGLCD.setBackColor(99, 171, 243);
// myGLCD.print(" ",(MaxX*razmer/2)+SmeX-110,158);
myGLCD.print("P A U S E", 180, 100);
myGLCD.setColor(BLACK);
myGLCD.drawLine(505, 29, 507 + 60, 29);
myGLCD.drawLine(505, 30, 507 + 60, 30);
delay(1000);
break;
}
}
}
// Получаем состояния всех кнопок в переменные valBtnL, valBtnR, valBtnT, valBtnD.
// Не играем: //
if (state == GAME_OFF) { // Если состояние игры равно GAME_OFF, то ...
if (valBtnL || valBtnR || valBtnT || valBtnD) { // Если нажата любая кнопка, то ...
state = GAME_ON; // Переводим состояние игры в GAME_ON (играем).
sumfig = 0; // Сбрасываем счётчик количества созданных фигур.
level1 = 1; // Сбрасываем счётчик текущего уровня.
points = 0; // Сбрасываем счётчик набранного количества балов.
tmrShift = 0; // Сбрасываем время следующего сдвига вниз фигуры на игровом столе.
valBtnD = 0; // Обнуляем состояние кнопки Down (состояние остальных кнопок обнулится при первом вызове функции getKeys).
memset(tableArray , 0, tableRows * 4); // Обнуляем массив tableArray заполняя нулями все tableRows его элементов по 4 байта каждый.
memset(figureArray , 0, 6 ); // Обнуляем массив figureArray заполняя нулями все 6 его элементов.
memset(figureArrayNew, 0, 6 ); // Обнуляем массив figureArrayNew заполняя нулями все 6 его элементов.
showGameScreen(); // Прорисовываем игровое поле.
createNewFigure(); // Создаём будущую фигуру. При этом новой фигуры на игровом столе ещё нет.
createNewFigure(); // Создаём будущую фигуру. Теперь ранее созданная будущая фигура стала новой фигурой на игровом столе.
} //
} else //
// Играем: //
if (state == GAME_ON) { // Если состояние игры равно GAME_ON, то ...
if (valBtnL)
{ valBtnL = 0;
shiftFigure(1);
} // Если нажата кнопка Left, то сдвигаем фигуру игрового стола влево на одну клетку.
if (valBtnR)
{ valBtnR = 0;
shiftFigure(2);
} // Если нажата кнопка Right, то сдвигаем фигуру игрового стола вправо на одну клетку.
if (valBtnT)
{ valBtnT = 0;
turnFigure(1);
} // Если нажата кнопка Turn, то поворачиваем фигуру игрового стола на 90° по часовой стрелке.
if (valBtnD || (millis() > tmrShift) ) { // Если нажата кнопка Down или наступило время очередного сдвига вниз фигуры на игровом столе, то ...
tmrShift = millis() + (startTime - ((level1 - 1) * changeTimeLevel)); // Обновляем время следующего сдвига вниз фигуры на игровом столе.
if (!shiftFigure(3)) { // Сдвигаем фигуру игрового стола на 1 клетку вниз. Если фигура достигла низа игрового стола или другой фигуры на игровом столе, то ...
if ( checkTable() ) {
points += deletTableRows(); // Проверяем наличие заполненных строк на игровом столе, если они есть, то удаляем заполненные строки, добавляя их количество в переменную points.
}
level1 = sumfig / sumToNewLevel + 1; // Определяем текущий уровень игры (он зависит от количества уже выведенных фигур).
sumfig++; // Увеличиваем счётчик созданных фигур.
// myOLED.setTextSize(2); // Указываем шрифт который требуется использовать для вывода цифр и текста.
// myOLED.setCursor(200,30);
myGLCD.setFont(Ubuntubold);
myGLCD.setColor(WHITE);
myGLCD.setBackColor(99, 171, 243);
// myOLED.setTextColor(WHITE, BIRD_BG);
// myOLED.print("LEVEL:"); // Выводим текст в указанную позицию на экране.
// myOLED.print( level ); // Выводим текущий уровень сразу после текста.
// myGLCD.print("LEVEL:",500,30);
myGLCD.printNumI( level1 , 45, 220);
// myOLED.setCursor(200,60);
// myOLED.print("SCORE:"); // Выводим текст в указанную позицию на экране.
// myOLED.print( points ); // Выводим текущий счёт сразу после текста.
//myGLCD.print("SCORE:",50,60);
myGLCD.printNumI( points , 45, 330);
if (valBtnD == 1) {
valBtnD = 0;
delay(1000);// Обнуляем состояние кнопки Down (состояние остальных кнопок обнулится при первом вызове функции getKeys).
}
if (!createNewFigure()) {
state = GAME_OVER; // Создаём будущую фигуру. Если создать фигуру невозможно, то переводим состояние игры в GAME_OVER (игра завершена).
}
} //
}
// **КНОПКИ ЦВЕТ*****************************
myGLCD.setColor(100, 100, 250);
myGLCD.drawLine(503, 29, 503 + 60, 29);
myGLCD.drawLine(503, 30, 503 + 60, 30);
myGLCD.drawLine(503, 239, 503 + 60, 239);
myGLCD.drawLine(503, 240, 503 + 60, 240);
myGLCD.drawLine(610, 132, 610 + 60, 132);
myGLCD.drawLine(610, 133, 610 + 60, 133);
myGLCD.drawLine(610, 344, 610 + 60, 344);
myGLCD.drawLine(610, 345, 610 + 60, 345);
myGLCD.drawLine(713, 239, 713 + 60, 239);
myGLCD.drawLine(713, 240, 713 + 60, 240);
//***************************************************
} else //
// Игра завершена: //
if (state == GAME_OVER) { // Если состояние игры равно GAME_OVER, то ...
for (uint8_t i = 0; i < tableRows; i++) {
tableArray[i] = 0xFFFFFFFF; // Выполняем анимацию построчного заполнения игрового стола сверху вниз.
delay(50);
showTable();
}
delay(1000);
for (uint8_t i = 0; i < tableRows; i++) {
tableArray[i] = 0; // Выполняем анимацию построчного очищения игрового стола сверху вниз.
delay(50);
showTable();
}
// myOLED.clrScr();
// myOLED.fillScreen(BIRD_BG);
// myGLCD.fillScr(BIRD_BG); // Чистим экран OLED дисплея.
// myOLED.setTextSize(4);
myGLCD.setColor(RED);
// myGLCD.setBackColor(BIRD_BG);
//myGLCD.print("GAME OVER" ,50,90);
myGLCD.print("GAME", 250, 100);
myGLCD.print("OVER", 250, 150);
// Указываем шрифт который требуется использовать для вывода цифр и текста.
// myOLED.setTextColor(GREEN , BIRD_BG);
// // Выводим текст по центру экрана.
while (1)
{ delay(100);
but();
if (myTouch.dataAvailable())
{
myTouch.read();
xt = myTouch.getX();
yt = myTouch.getY();
valBtnT = 1;
if ((xt >= 750) && (xt <= 790)) // Upper row
{
if ((yt >= 10) && (yt <= 60)) // Button: 1
{ valBtnT = 1;
exit_menu = 1; //ВЫХОД
}
}
}
if (valBtnL || valBtnR || valBtnT || valBtnD)
{ valBtnPause = 0;
valBtnT = 1;
break;
}
} // Ждём.
showWelcome(); // Выводим анимированное приветствие.
valBtnD = 0; // Обнуляем состояние кнопки Down (состояние остальных кнопок обнулится при первом вызове функции getKeys).
state = GAME_OFF; // Переводим состояние игры в GAME_OFF.
}
} //
}
//
// Значения возвращаемые функцией: нет.
void showWelcome() { // Аргументы принимаемые функцией: нет.
// myOLED.autoUpdate(true); // Разрешаем автоматический вывод данных без обращения к функции myOLED.update().
myGLCD.fillScr(99, 171, 243); // Чистим экран OLED дисплея. // Чистим экран OLED дисплея.
// myOLED.setTextSize(4); // Указываем шрифт который требуется использовать для вывода цифр и текста.
// myOLED.setCursor(90,105);
//myOLED.setTextColor(YELLOW, BIRD_BG);
// myOLED.print("TETRIS") ; // Выводим текст по центру экрана.
myFiles.load(0, 0, 800, 480, "play/18.raw" , 32, 0);
// myGLCD.setColor(YELLOW);
// myGLCD.setBackColor(BIRD_BG);
// myGLCD.print("TETRIS" ,90,105);
// Ждём
while (1)
{ delay(100);
but();
if (myTouch.dataAvailable())
{
myTouch.read();
xt = myTouch.getX();
yt = myTouch.getY();
valBtnT = 1;
if ((xt >= 750) && (xt <= 790)) // Upper row
{
if ((yt >= 10) && (yt <= 60)) // Button: 1
{ valBtnT = 1;
exit_menu = 1; //ВЫХОД
}
}
}
if (valBtnL || valBtnR || valBtnT || valBtnD)
{ valBtnPause = 0;
valBtnT = 1;
break;
}
}
}
//
//
// Прорисовка игрового поля: // Значения возвращаемые функцией: нет.
void showGameScreen(void) { // Аргументы принимаемые функцией: нет.
myGLCD.fillScr(99, 171, 243); // Чистим экран OLED дисплея. // Чистим экран OLED дисплея.
// myGLCD.setFont(BigFont);
myGLCD.setFont(Ubuntubold);// Указываем шрифт который требуется использовать для вывода цифр и текста.
myFiles.load(0, 0, 800, 480, "play/19.raw" , 32, 0);
myGLCD.setColor(WHITE);
// myOLED.drawRect(0,0,tableCols*(tableCubeSize+1)+2,tableRows*(tableCubeSize+1)+2,WHITE); // Выводим рамку игрового стола.
myGLCD.drawRect(Xsm, Ysm, Xsm + tableCols * (tableCubeSize + 1) + 2, Ysm + tableRows * (tableCubeSize + 1) + 2); // Выводим рамку игрового стола.
myGLCD.setColor(WHITE);
myGLCD.setBackColor(99, 171, 243);
// myGLCD.print("LEVEL:",50,30);
myGLCD.printNumI( level1 , 45, 220);
// myGLCD.print("SCORE:",500,60);
// myGLCD.printNumI( points ,50,380);
myGLCD.printNumI( points , 45, 330); // Обновляем информацию на экране OLED дисплея.
}
// Создание будущей фигуры: // Значения возвращаемые функцией: функция вернёт false если вставить ранее созданную будущую фигуру на игровой стол не удается (завершение игры).
bool createNewFigure() { // Аргументы принимаемые функцией: нет.
// Превращаем ранее созданную будущую фигуру в новую фигуру на игровом столе: //
memcpy(figureArray, figureArrayNew, 6); // Копируем ранее созданную будущую фигуру в новую фигуру на игровом столе (копируем все 6 элементов массива figureArrayNew в массив figureArray).
figcol1 = figcol; // передача цвета
figurePos[0] = figurePos[2]; // Определяем отсуп слева для новой фигуры на игровом столе из начального отступа для новой фигуры.
figurePos[1] = figurePos[3]; // Определяем отступ сверху для новой фигуры на игровом столе из начального отступа для новой фигуры.
if (!shiftFigure(0)) {
return false; // Выводим новую фигуру на игровой стол и возвращаем false если положение этой фигуры некорректно.
}
// Создаём будущую фигуру: //
switch (random(7)) { // Переходим к созданию будущей фигуры, в зависимости от случайного числа со значением от 0 до 6 включительно...
case 0: // Если случайное число равно 0, то создаём фигуру...
figureArrayNew[0] = B00000; //
figureArrayNew[1] = B01000; // #
figureArrayNew[2] = B01110; // ###
figureArrayNew[3] = B00000; //
figureArrayNew[4] = B00000; //
figureArrayNew[5] = 0; // Нет запрета на поворот фигуры.
figcol = 1;
break; //
case 1: // Если случайное число равно 1, то создаём фигуру...
figureArrayNew[0] = B00000; //
figureArrayNew[1] = B00000; //
figureArrayNew[2] = B01110; // ###
figureArrayNew[3] = B01000; // #
figureArrayNew[4] = B00000; //
figureArrayNew[5] = 0; // Нет запрета на поворот фигуры.
figcol = 2;
break; //
case 2: // Если случайное число равно 2, то создаём фигуру...
figureArrayNew[0] = B00000; //
figureArrayNew[1] = B00100; // #
figureArrayNew[2] = B01110; // ###
figureArrayNew[3] = B00000; //
figureArrayNew[4] = B00000; //
figureArrayNew[5] = 0; // Нет запрета на поворот фигуры.
figcol = 4;
break; //
case 3: // Если случайное число равно 3, то создаём фигуру...
figureArrayNew[0] = B00000; //
figureArrayNew[1] = B01100; // ##
figureArrayNew[2] = B00110; // ##
figureArrayNew[3] = B00000; //
figureArrayNew[4] = B00000; //
figureArrayNew[5] = 0; // Нет запрета на поворот фигуры.
figcol = 3;
break; //
case 4: // Если случайное число равно 4, то создаём фигуру...
figureArrayNew[0] = B00000; //
figureArrayNew[1] = B00110; // ##
figureArrayNew[2] = B01100; // ##
figureArrayNew[3] = B00000; //
figureArrayNew[4] = B00000; //
figureArrayNew[5] = 0; // Нет запрета на поворот фигуры.
figcol = 5;
break; //
case 5: // Если случайное число равно 5, то создаём фигуру...
figureArrayNew[0] = B00000; //
figureArrayNew[1] = B01100; // ##
figureArrayNew[2] = B01100; // ##
figureArrayNew[3] = B00000; //
figureArrayNew[4] = B00000; //
figureArrayNew[5] = 1; // Есть запрет на поворот фигуры.
figcol = 6;
break; //
case 6: // Если случайное число равно 6, то создаём фигуру...
figureArrayNew[0] = B00100; // #
figureArrayNew[1] = B00100; // #
figureArrayNew[2] = B00100; // #
figureArrayNew[3] = B00100; // #
figureArrayNew[4] = B00000; //
figureArrayNew[5] = 0; // Нет запрета на поворот фигуры.
figcol = 7;
break; //
} //
turnFigure(0, random(4)); // Поворачиваем созданную будущую фигуру на 90°. Случайное число от 0 до 3 включительно, указывает сколько раз требуется повернуть будущую фигуру.
return true; // Возвращаем true. Новая фигура установлена на игровом столе и будущая фигура создана.
} //
//****************************************************************************************************************************************************
// Прорисовка или затирание фигуры: // Значения возвращаемые функцией: нет.
void showFigure(bool i, bool j, int color) { // Аргументы принимаемые функцией: i - флаг (1-фигура на игровом столе, 0-будущая фигура), j - флаг (1-прорисовать фигуру, 0-затереть фигуру).
int x0, y0; // Объявляем переменные для хранения координат верхнего левого угла массива фигуры в пикселях.
int x1, y1; // Объявляем переменные для хранения координат верхнего левого угла кубика фигуры в пикселях.
int16_t s = i ? tableCubeSize : newCubeSize; // Определяем размер кубиков фигуры.
if (i) { // Если первый аргумент функции равен 1, то ...
// Прорисовываем или затираем фигуру на игровом столе: //
x0 = 2 + figurePos[0] * (s + 1); // Определяем координату левого угла массива фигуры в пикселях.
y0 = 2 + figurePos[1] * (s + 1); // Определяем координату верхнего угла массива фигуры в пикселях.
for (uint8_t row = 0; row < 5; row++) {
y1 = row * (s + 1); // Проходим по клеткам фигуры сверху вниз (строкам).
for (uint8_t col = 0; col < 5; col++) {
x1 = col * (s + 1); // Проходим по клеткам фигуры справа на лево (колонкам).
if (bitRead(figureArray[row], 4 - col)) { // Если бит 4-col элемента row массива figureArray равен 1, значит кубик есть, тогда ...
if (y0 + y1 > 1) { // Если позиция кубика находится в области игрового стола, тогда ...
// Прорисовываем закрашенный кубик на игровом столе.
if (j == 1)
{ myGLCD.setColor(arrPins1[color]);
myGLCD.fillRect(Xsm + x0 + x1, Ysm + y0 + y1, Xsm + x0 + x1 + s - 1, Ysm + y0 + y1 + s - 1); // Прорисовываем закрашенный кубик на игровом столе.
myGLCD.setColor(WHITE);
myGLCD.drawRect(Xsm + x0 + x1, Ysm + y0 + y1, Xsm + x0 + x1 + s - 1, Ysm + y0 + y1 + s - 1);
}
else {
myGLCD.setColor(99, 171, 243);
//myOLED.fillRect(x0+x1, y0+y1, s-1, s-1, BIRD_BG);// затираем закрашенный кубик на игровом столе.
myGLCD.fillRect(Xsm + x0 + x1, Ysm + y0 + y1, Xsm + x0 + x1 + s - 1, Ysm + y0 + y1 + s - 1);
}
}
}
}
} //
} else { // Если первый аргумент функции равен 0, то ...
// Прорисовываем или затираем будущую фигуру: //
// x0 = scrBoundary; // Определяем координату левого угла массива фигуры в пикселях.
x0 = 5 - Xsm;
y0 = 35 - Ysm; // Определяем координату верхнего угла массива фигуры в пикселях.
if (j) { // Если второй аргумент функции равен 1, то ...
// Прорисовываем будущую фигуру: //
for (uint8_t row = 0; row < 5; row++) {
y1 = row * (s + 1); // Проходим по клеткам фигуры сверху вниз (строкам).
for (uint8_t col = 0; col < 5; col++) {
x1 = col * (s + 1); // Проходим по клеткам фигуры справа на лево (колонкам).
if (bitRead(figureArrayNew[row], 4 - col)) {
myGLCD.setColor(arrPins1[color]);
myGLCD.fillRect(Xsm + x0 + x1, Ysm + y0 + y1, Xsm + x0 + x1 + s - 1, Ysm + y0 + y1 + s - 1); // Прорисовываем не закрашенный квадрат белого цвета.
myGLCD.setColor(WHITE);
myGLCD.drawRect(Xsm + x0 + x1, Ysm + y0 + y1, Xsm + x0 + x1 + s - 1, Ysm + y0 + y1 + s - 1);
}
}
} //
} else { // Если второй аргумент функции равен 0, то ...
// Затираем место под будущую фигуру: //
myGLCD.setColor(99, 171, 243);
myGLCD.fillRect(Xsm + x0 + 2, Ysm + y0, Xsm + x0 + 5 * (s + 1) - 2, Ysm + y0 + 5 * (s + 1)); // Прорисовываем закрашенный квадрат черного цвета покрывая всю площадь предназначенную для вывода будущих фигур.
} //
} //
} //
//
// Прорисовка всех кубиков в клетках игрового стола: // Значения возвращаемые функцией: нет.
void showTable() { // Аргументы принимаемые функцией: нет.
int x, y; // Объявляем переменные для хранения координат верхнего левого угла клетки игрового стола в пикселях.
int s = tableCubeSize; // Определяем размер клеток игрового стола.
for (uint8_t row = 0; row < tableRows; row++) {
y = 2 + row * (s + 1); // Проходим по клеткам игрового стола сверху вниз (строкам).
for (uint8_t col = 0; col < tableCols; col++) {
x = 2 + (tableCols - col - 1) * (s + 1); // Проходим по клеткам игрового стола справа на лево (колонкам).
// myOLED.drawRect(x, y, x+s-1, y+s-1, true, bitRead(tableArray[row], col)); // Прорисовываем кубики в клетках игрового стола.
if (bitRead(tableArray[row], col))
{ myGLCD.setColor(RED);
myGLCD.fillRect(Xsm + x, Ysm + y, Xsm + x + s - 1, Ysm + y + s - 1);
myGLCD.setColor( WHITE);
myGLCD.drawRect(Xsm + x, Ysm + y, Xsm + x + s - 1, Ysm + y + s - 1);
}
else {
myGLCD.setColor(99, 171, 243);
myGLCD.fillRect(Xsm + x, Ysm + y, Xsm + x + s - 1, Ysm + y + s - 1);
}
} //
} //
} //
//
//
// Поворот фигуры на 90° по часовой стрелке: // Значения возвращаемые функцией: нет.
void turnFigure(bool i, uint8_t j) { // Аргументы принимаемые функцией: i - флаг (1-фигура на игровом столе, 0-будущая фигура), j - количество поворотов на 90° по часовой стрелке (только для будущей фигуры).
uint8_t figureArrayTemp[5]; // Объявляем временный массив для хранения изначального вида фигуры.
if (i) { // Если первый аргумент функции равен 1, то ...
// Поворачиваем фигуру на игровом столе: //
if (figureArray[5] == 0) { // Если фигуру на игровом столе не запрещено поворачивать, то ...
showFigure(1, 0, 0); // Затираем фигуру на игровом столе.
memcpy(figureArrayTemp, figureArray, 5); // Копируем 5 элементов массива figureArray в массив figureArrayTemp.
memset(figureArray, 0, 5); // Обнуляем изображение фигуры в массиве figureArray заполняя нулями 5 его элементов.
for (uint8_t k = 0; k < 5; k++) { // Проходим по элементам массива figureArrayNew и битам элементов массива figureArrayTemp.
for (uint8_t l = 0; l < 5; l++) { // Проходим по элементам массива figureArrayTemp и битам элементов массива figureArrayNew.
bitWrite(figureArray[4 - k], l, bitRead(figureArrayTemp[l], k) ); // Заполняем массив figureArrayNew повернутым массивом figureArrayTemp.
} //
} //
if (!checkFigure()) {
memcpy(figureArray, figureArrayTemp, 5); // Проверяем корректность положения фигуры на игровом столе. Если положение не корректно, то возвращаем начальное значение массива figureArray из figureArrayTemp.
}
showFigure(1, 1, figcol1); // Прорисовываем фигуру на игровом столе.
} //
} else { // Если первый аргумент функции равен 0, то ...
// Поворачиваем будущую фигуру: //
showFigure(0, 0, 0); // Затираем предыдущую будущую фигуру.
if (figureArrayNew[5] == 0) { // Если будущую фигуру не запрещено поворачивать, то ...
for (uint8_t n = 0; n < j; n++) { // Выполняем поворот фигуры на 90° указанное число раз.
memcpy(figureArrayTemp, figureArrayNew, 5); // Копируем 5 элементов массива figureArrayNew в массив figureArrayTemp.
memset(figureArrayNew, 0, 5); // Обнуляем изображение фигуры в массиве figureArrayNew заполняя нулями 5 его элементов.
for (uint8_t k = 0; k < 5; k++) { // Проходим по элементам массива figureArrayNew и битам элементов массива figureArrayTemp.
for (uint8_t l = 0; l < 5; l++) { // Проходим по элементам массива figureArrayTemp и битам элементов массива figureArrayNew.
bitWrite(figureArrayNew[4 - k], l, bitRead(figureArrayTemp[l], k) ); // Заполняем массив figureArrayNew повернутым массивом figureArrayTemp.
} //
} //
} //
} //
figurePos[3] = 0; // Начальный отступ новой фигуры сверху равен 0 клеток.
while (figureArrayNew[ (figurePos[3] * (-1)) ] == 0) {
figurePos[3]--; // Если очередная сверху строка клеток будущей фигуры пуста, то уменьшаем начальный отступ сверху для новой фигуры (т.к. отступ может получиться отрицательным, то новая фигура будет сдвинута вверх при появлении на игровом столе).
}
showFigure(0, 1, figcol); // Прорисовываем созданную фигуру.
} //
} //
//
// Cдвиг фигуры на одну клетку игрового стола: // Значения возвращаемые функцией: Функция вернёт false если сдвиг фигуры невозможен.
bool shiftFigure(uint8_t i) { // Аргументы принимаемые функцией: i = 1 - влево, 2 - вправо, 3 - вниз, иначе - без сдвига.
switch (i) { // Переходим к сдвигу фигуры игрового стола на одну клетку, в направлении зависящем от аргумента функции ...
case 1: figurePos[0]--; // Если фигуру требуется сдвинуть влево, то уменьшаем отступ фигуры слева на 1 клетку.
if (checkFigure()) {
figurePos[0]++; showFigure(1, 0, figcol1); // Если положение фигуры корректно, то возвращаем отступ фигуры и затираем фигуру на игровом столе.
figurePos[0]--; showFigure(1, 1, figcol1); // Опять уменьшаем отступ фигуры слева и прорисовываем фигуру на новом месте игрового стола.
} else {
figurePos[0]++; // Иначе, если положение фигуры не корректно, то возвращаем отступ фигуры слева и возвращаем false.
return false;
}
break; //
case 2: figurePos[0]++; // Если фигуру требуется сдвинуть вправо, то увеличиваем отступ фигуры слева на 1 клетку.
if (checkFigure()) {
figurePos[0]--; showFigure(1, 0, figcol1); // Если положение фигуры корректно, то возвращаем отступ фигуры и затираем фигуру на игровом столе.
figurePos[0]++; showFigure(1, 1, figcol1); // Увеличиваем отступ фигуры слева и прорисовываем фигуру на новом месте игрового стола.
} else {
figurePos[0]--; // Иначе, если положение фигуры не корректно, то возвращаем отступ фигуры слева и возвращаем false.
return false;
}
break; //
case 3: figurePos[1]++; // Если фигуру требуется сдвинуть вниз, то увеличиваем отступ фигуры сверху на 1 клетку.
if (checkFigure()) {
figurePos[1]--; showFigure(1, 0, figcol1); // Если положение фигуры корректно, то возвращаем отступ фигуры и затираем фигуру на игровом столе.
figurePos[1]++; showFigure(1, 1, figcol1); // Увеличиваем отступ фигуры и прорисовываем фигуру на новом месте игрового стола.
} else {
figurePos[1]--; // Иначе, если положение фигуры не корректно, то возвращаем отступ фигуры и возвращаем false.
return false;
}
break; //
default: showFigure(1, 1, figcol1); return checkFigure(); // Если фигуру не требуется сдвигать, то прорисовываем фигуру в её текущей позиции игрового стола и возвращаем результат корректности положения фигуры.
break; //
} //
delay(50);
return true; //
} //
//
// Проверка корректности положения фигуры на игровом столе: // Значения возвращаемые функцией: функция вернёт false если положение фигуры на игровом столе некорректно.
bool checkFigure() { // Аргументы принимаемые функцией: нет.
int8_t x = tableCols - figurePos[0] - 1; // Определяем отступ массива фигуры на игровом столе от его левого края в клетках.
for (uint8_t row = 0; row < 5; row++) { // Проходим по клеткам фигуры сверху вниз (строкам).
for (uint8_t col = 0; col < 5; col++) { // Проходим по клеткам фигуры справа на лево (колонкам).
if (bitRead(figureArray[row], col)) { // Если бит col элемента row массива figureArrayNew равен 1, значит кубик есть, тогда ...
if (figurePos[1] + row >= tableRows) {
return false; // Если позиция кубика фигуры превышает количество строк (клеток по вертикали) игрового стола, значит положение фигуры некорректно (фигура вышла за нижнюю границу игрового стола).
}
if (x - (4 - col) >= tableCols) {
return false; // Если позиция кубика фигуры превышает количество столбцов (клеток по горизонтали) игрового стола, значит положение фигуры некорректно (фигура вышла за левую границу игрового стола).
}
if (x - (4 - col) < 0 ) {
return false; // Если позиция кубика фигуры находится в отрицательном столбце (клетке) игрового стола, значит положение фигуры некорректно (фигура вышла за правую границу игрового стола).
}
if (bitRead(tableArray[figurePos[1] + row], x - (4 - col))) {
return false; // Если позиция кубика фигуры наложилась на кубик в клетке игрового стола, значит положение фигуры некорректно (фигура наложилась на уже имеющуюся фигуру игрового стола).
}
} //
} //
} //
return true; //
} //
//
// Проверка заполненных строк на игровом столе: // Значения возвращаемые функцией: функция вернёт true если на игровом столе есть полностью заполненные строки.
bool checkTable() { // Аргументы принимаемые функцией: нет.
// Добавляем фигуру игрового стола в массив клеток игрового стола: //
for (uint8_t row = 0; row < 5; row++) { // Проходим по клеткам фигуры сверху вниз (строкам).
for (uint8_t col = 0; col < 5; col++) { // Проходим по клеткам фигуры справа на лево (колонкам).
if (bitRead(figureArray[row], col)) { // Если бит col элемента row массива figureArrayNew равен 1, значит кубик есть, тогда ...
bitSet(tableArray[figurePos[1] + row], tableCols - figurePos[0] - (4 - col) - 1); // Устанавливаем в 1 бит массива tableArray соответствующий клетке игрового стола на которой находится кубик фигуры.
} //
} //
} //
// Проверяем игровой стол на наличие полных строк: //
uint32_t fullRows = 0; // Определяем переменную, значение которой будет эталоном для заполненной строки игрового стола.
for (uint8_t i = 0; i < tableCols; i++) {
bitSet(fullRows, i); // Заполняем переменную fullRows эталонным значением.
}
for (uint8_t i = 0; i < tableRows; i++) {
if (tableArray[i] == fullRows) {
return true; // Проходим по строкам игрового стола (сверху вниз) в поисках совпадений с эталонным значением. Если совпадение найдено - возвращаем true.
}
}
return false; // Возвращаем false.
} //
//
// Удаление заполненных строк с игрового стола: // Значения возвращаемые функцией: функция вернёт количество удалённых строк.
uint8_t deletTableRows() { // Аргументы принимаемые функцией: нет.
uint8_t sum = 0; // Определяем счётчик стёртых строк.
uint32_t fullRows = 0; // Определяем переменную, значение которой будет эталоном для заполненной строки игрового стола.
for (uint8_t i = 0; i < tableCols; i++) {
bitSet(fullRows, i); // Заполняем переменную fullRows эталонным значением.
}
for (uint8_t i = 0; i < tableRows; i++) {
if (tableArray[i] == fullRows) {
tableArray[i] = 0; // Проходим по строкам игрового стола (сверху вниз) в поисках совпадений с эталонным значением. Если совпадение найдено - увеличиваем счётчик и обнуляем строку.
sum++;
}
}
if (sum) { // Если были обнулены строки игрового стола, то ...
showTable(); // Прорисовываем игровой стол с обнулёнными (пустыми) строками.
delay(500); // Вызываем задержку, чтоб пустые строки можно было увидеть
for (uint8_t i = 0; i < tableRows; i++) { // Проходим по строкам игрового стола (сверху вниз) в поисках пустых строк.
if (tableArray[i] == 0) { // Если пустая строка обнаружена, то ...
for (int8_t j = i; j > 0; j--) {
tableArray[j] = tableArray[j - 1]; // Сдвигаем все строки находящиеся выше вниз, на одну строку (клетку).
}
} //
} //
showTable(); // Прорисовываем игровой стол с удалёнными пустыми строками.
} //
return sum; // Возвращаем количество удалённых пустых строк.
}