Код:
#include
#include
#include
#include "GyverButton.h"
#define OLED_DC 26
#define OLED_CS 31
#define OLED_RESET 24
#define BLOCK_WIDTH 4
#define FRAME_WIDTH 12
#define FRAME_HEIGHT 23
#define BTN1 2
#define BTN2 12
#define BTN3 13
#define BuzzerPin 15
#define NORMAL_SPEED 300
#define FAST_SPEED 20
Adafruit_SSD1306 display(OLED_DC, OLED_RESET, OLED_CS);
GButton btn1(BTN1, LOW_PULL, NORM_OPEN);
GButton btn2(BTN2, LOW_PULL, NORM_OPEN);
GButton btn3(BTN3, LOW_PULL, NORM_OPEN);
struct point_t
{
byte x;
byte y;
};
struct figure_t
{
point_t points[4];
point_t pos = {FRAME_WIDTH / 2 - 1, FRAME_HEIGHT - 3};
int rotation = 0;
};
int gameSpeed = 100;
const long buttonsPressSteep = 100;
unsigned long previousMillis = 0;
unsigned long buttonsPreviousMillis = 0;
bool gameStatus = true;
byte score = 0;
bool playingField[FRAME_WIDTH][FRAME_HEIGHT];
figure_t j_figure;
figure_t i_figure;
figure_t o_figure;
figure_t z_figure;
figure_t figures[4];
figure_t nextFigure;
figure_t curFigure;
void setup()
{
randomSeed(analogRead(A5));
InitFugures();
display.begin(SSD1306_SWITCHCAPVCC);
display.setRotation(1);
display.display();
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
StartGame();
}
void loop() {
display.clearDisplay();
display.drawRect(0, 10, 63, 128 - 10, WHITE);
TimerUpdate();
UpdateEveryFrame();
display.display();
}
void UpdateEveryFrame()
{
display.setCursor(0, 0);
display.println(score);
DrawPlayingField();
DrawNextFigure();
DrawFigure(curFigure);
btn1.tick();
btn2.tick();
btn3.tick();
if (!gameStatus)
{
display.setCursor(5, 12);
display.println("Game Over");
}
}
void Update()
{
curFigure.pos.y--;
Colision(curFigure);
}
void Colision(figure_t figure)
{
for (byte i = 0 ; i < 4; i++)
{
byte xPos = figure.pos.x + figure.points[i].x;
byte yPos = figure.pos.y + figure.points[i].y;
//Ground check
if (yPos == 0)
{
AddFigureToField(figure);
CheckFilledRow();
GenerateNextFigure();
return;
}
if (playingField[xPos][yPos - 1])
{
if (FindMaxY(figure) == FRAME_HEIGHT - 3)
{
GameOver();
return;
}
AddFigureToField(figure);
CheckFilledRow();
GenerateNextFigure();
return;
}
}
}
void Rotate(figure_t& figure)
{
figure.rotation += 90;
if (figure.rotation >= 360)
figure.rotation -= 360;
for (byte i = 0 ; i < 4; i++)
{
byte tempX = figure.points[i].x;
figure.points[i].x = figure.points[i].y;
figure.points[i].y = tempX;
}
}
void Buttons()
{
if (btn3.state())
{
if (!gameStatus)
{
StartGame();
}
else
{
if (FindMinX(curFigure) != 0)
{
bool canMove = true;
for (byte i = 0 ; i < 4; i++)
{
byte xPos = curFigure.pos.x + curFigure.points[i].x;
byte yPos = curFigure.pos.y + curFigure.points[i].y;
if (playingField[xPos - 1][yPos])
{
canMove = false;
break;
}
}
if (canMove)
{
curFigure.pos.x--;
Colision(curFigure);
}
}
}
}
if (btn1.state())
{
if (!gameStatus)
{
StartGame();
}
else
{
if (FindMaxX(curFigure) != FRAME_WIDTH - 1)
{
bool canMove = true;
for (byte i = 0 ; i < 4; i++)
{
byte xPos = curFigure.pos.x + curFigure.points[i].x;
byte yPos = curFigure.pos.y + curFigure.points[i].y;
if (playingField[xPos + 1][yPos])
{
canMove = false;
break;
}
}
if (canMove)
{
curFigure.pos.x++;
Colision(curFigure);
}
}
}
}
if (btn2.isHold())
{
gameSpeed = FAST_SPEED;
tone(BuzzerPin, 2000);
}
if (btn2.isRelease())
{
gameSpeed = NORMAL_SPEED;
tone(BuzzerPin, 5000, 400);
}
if (btn2.isClick())
{
if (!gameStatus)
{
StartGame();
}
else
Rotate(curFigure);
}
}
void AddScore()
{
score++;
tone(BuzzerPin, 3000, 300);
tone(BuzzerPin, 6000, 200);
tone(BuzzerPin, 2000, 300);
}
void StartGame()
{
for (byte y = 0 ; y < 23; y++)
for (byte x = 0 ; x < 12; x++)
playingField[x][y] = false;
score = 0;
gameStatus = true;
nextFigure = figures[random(4)];
curFigure = figures[random(4)];
//nextFigure = o_figure;
//curFigure = o_figure;
}
void GameOver()
{
gameStatus = false;
}
void GenerateNextFigure()
{
curFigure = nextFigure;
nextFigure = figures[random(4)];
//nextFigure = o_figure;
}
void AddFigureToField(figure_t figure)
{
for (byte i = 0; i < 4; i++)
{
playingField[figure.pos.x + figure.points[i].x][ figure.pos.y + figure.points[i].y] = true;
}
}
void CheckFilledRow()
{
for (byte k = 0; k < 4; k++)
{
for (byte y = 0; y < FRAME_HEIGHT - 1; y++)
{
bool filledRow = true;
for (byte x = 0; x < FRAME_WIDTH; x++)
{
if (!playingField[x][y])
{
filledRow = false;
break;
}
}
if (filledRow)
{
AddScore();
for (byte i = y; i < FRAME_HEIGHT - 1; i++)
{
for (byte j = 0; j < FRAME_WIDTH; j++)
{
playingField[j][i] = playingField[j][i + 1];
}
}
}
}
}
}
void DrawBlock(byte x, byte y, byte color = WHITE)
{
display.fillRect(2 + (x * (BLOCK_WIDTH + 1)), 128 - 1 - 10 - ((y - 1) * (BLOCK_WIDTH + 1)), BLOCK_WIDTH, BLOCK_WIDTH, color);
}
void DrawFigure(figure_t figure, byte x, byte y)
{
for (byte i = 0 ; i < 4; i++)
DrawBlock(x + figure.points[i].x, y + figure.points[i].y);
}
void DrawFigure(figure_t figure)
{
DrawFigure(figure, figure.pos.x, figure.pos.y);
}
void DrawNextFigure()
{
for (byte i = 0 ; i < 4; i++)
display.fillRect(44 + (nextFigure.points[i].x * (BLOCK_WIDTH + 1)), (nextFigure.points[i].y * (BLOCK_WIDTH + 1)), BLOCK_WIDTH, BLOCK_WIDTH, WHITE);
}
void DrawPlayingField()
{
for (byte y = 0 ; y < 23; y++)
for (byte x = 0 ; x < 12; x++)
{
DrawBlock(x, y);
if (playingField[x][y])
DrawBlock(x, y, WHITE);
else
DrawBlock(x, y, BLACK);
}
}
void TimerUpdate()
{
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= gameSpeed)
{
previousMillis = currentMillis;
if (gameStatus)
Update();
}
if (currentMillis - buttonsPreviousMillis >= buttonsPressSteep)
{
buttonsPreviousMillis = currentMillis;
Buttons();
}
}
byte FindMinX(figure_t figure)
{
byte xPos = figure.pos.x + figure.points[0].x;
for (byte i = 1 ; i < 4; i++)
if (xPos > figure.pos.x + figure.points[i].x)
xPos = figure.pos.x + figure.points[i].x;
return xPos;
}
byte FindMaxX(figure_t figure)
{
byte xPos = figure.pos.x + figure.points[0].x;
for (byte i = 1 ; i < 4; i++)
if (xPos < figure.pos.x + figure.points[i].x)
xPos = figure.pos.x + figure.points[i].x;
return xPos;
}
byte FindMinY(figure_t figure)
{
byte yPos = figure.pos.y + figure.points[0].y;
for (byte i = 1 ; i < 4; i++)
if (yPos > figure.pos.y + figure.points[i].y)
yPos = figure.pos.y + figure.points[i].y;
return yPos;
}
byte FindMaxY(figure_t figure)
{
byte yPos = figure.pos.y + figure.points[0].y;
for (byte i = 1 ; i < 4; i++)
if (yPos < figure.pos.y + figure.points[i].y)
yPos = figure.pos.y + figure.points[i].y;
return yPos;
}
void InitFugures()
{
j_figure.points[0] = {0, 0};
j_figure.points[1] = {0, 1};
j_figure.points[2] = {1, 1};
j_figure.points[3] = {2, 1};
i_figure.points[0] = {0, 0};
i_figure.points[1] = {1, 0};
i_figure.points[2] = {2, 0};
i_figure.points[3] = {3, 0};
o_figure.points[0] = {0, 0};
o_figure.points[1] = {0, 1};
o_figure.points[2] = {1, 0};
o_figure.points[3] = {1, 1};
z_figure.points[0] = {0, 0};
z_figure.points[1] = {1, 0};
z_figure.points[2] = {1, 1};
z_figure.points[3] = {2, 1};
figures[0] = j_figure;
figures[1] = i_figure;
figures[2] = o_figure;
figures[3] = z_figure;
}