123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- //========================================================================
- // TETRIS with M5STACK : 2018.01.20 Transplant by macsbug
- // Controller : Buttons A = LEFT, B = RIGHT, C = START, ROTATE
- // Display : Left = 100x240, Center = 120x240, Right = 100x240
- // Block : 8ea, 12x12 pixel
- // SD : tetris.jpg : BackGround Image : R.G.B 320x240 pixel
- // Github : https://macsbug.wordpress.com/2018/01/20/tetris-with-m5stack/
- //========================================================================
- #include <M5Stack.h> // M5STACK
- uint16_t BlockImage[8][12][12]; // Block
- uint16_t backBuffer[240][120]; // GAME AREA
- const int Length = 12; // the number of pixels for a side of a block
- const int Width = 10; // the number of horizontal blocks
- const int Height = 20; // the number of vertical blocks
- int screen[Width][Height] = {0}; // it shows color-numbers of all positions
- struct Point {
- int X, Y;
- };
- struct Block {
- Point square[4][4];
- int numRotate, color;
- };
- Point pos;
- Block block;
- int rot, fall_cnt = 0;
- bool started = false, gameover = false;
- boolean but_A = false, but_LEFT = false, but_RIGHT = false;
- int game_speed = 25; // 25msec
- Block blocks[7] = {{{{{-1, 0}, {0, 0}, {1, 0}, {2, 0}},
- {{0, -1}, {0, 0}, {0, 1}, {0, 2}},
- {{0, 0}, {0, 0}, {0, 0}, {0, 0}},
- {{0, 0}, {0, 0}, {0, 0}, {0, 0}}},
- 2,
- 1},
- {{{{0, -1}, {1, -1}, {0, 0}, {1, 0}},
- {{0, 0}, {0, 0}, {0, 0}, {0, 0}},
- {{0, 0}, {0, 0}, {0, 0}, {0, 0}},
- {{0, 0}, {0, 0}, {0, 0}, {0, 0}}},
- 1,
- 2},
- {{{{-1, -1}, {-1, 0}, {0, 0}, {1, 0}},
- {{-1, 1}, {0, 1}, {0, 0}, {0, -1}},
- {{-1, 0}, {0, 0}, {1, 0}, {1, 1}},
- {{1, -1}, {0, -1}, {0, 0}, {0, 1}}},
- 4,
- 3},
- {{{{-1, 0}, {0, 0}, {0, 1}, {1, 1}},
- {{0, -1}, {0, 0}, {-1, 0}, {-1, 1}},
- {{0, 0}, {0, 0}, {0, 0}, {0, 0}},
- {{0, 0}, {0, 0}, {0, 0}, {0, 0}}},
- 2,
- 4},
- {{{{-1, 0}, {0, 0}, {1, 0}, {1, -1}},
- {{-1, -1}, {0, -1}, {0, 0}, {0, 1}},
- {{-1, 1}, {-1, 0}, {0, 0}, {1, 0}},
- {{0, -1}, {0, 0}, {0, 1}, {1, 1}}},
- 4,
- 5},
- {{{{-1, 1}, {0, 1}, {0, 0}, {1, 0}},
- {{0, -1}, {0, 0}, {1, 0}, {1, 1}},
- {{0, 0}, {0, 0}, {0, 0}, {0, 0}},
- {{0, 0}, {0, 0}, {0, 0}, {0, 0}}},
- 2,
- 6},
- {{{{-1, 0}, {0, 0}, {1, 0}, {0, -1}},
- {{0, -1}, {0, 0}, {0, 1}, {-1, 0}},
- {{-1, 0}, {0, 0}, {1, 0}, {0, 1}},
- {{0, -1}, {0, 0}, {0, 1}, {1, 0}}},
- 4,
- 7}};
- extern uint8_t tetris_img[];
- //========================================================================
- void setup(void) {
- M5.begin(); // M5STACK INITIALIZE
- M5.Power.begin();
- M5.Lcd.setBrightness(200); // BRIGHTNESS = MAX 255
- M5.Lcd.fillScreen(BLACK); // CLEAR SCREEN
- //----------------------------// Make Block ----------------------------
- make_block(0, BLACK); // Type No, Color
- make_block(1, 0x00F0); // DDDD RED
- make_block(2, 0xFBE4); // DD,DD PUPLE
- make_block(3, 0xFF00); // D__,DDD BLUE
- make_block(4, 0xFF87); // DD_,_DD GREEN
- make_block(5, 0x87FF); // __D,DDD YELLO
- make_block(6, 0xF00F); // _DD,DD_ LIGHT GREEN
- make_block(7, 0xF8FC); // _D_,DDD PINK
- //----------------------------------------------------------------------
- // M5.Lcd.drawJpgFile(SD, "/tetris.jpg"); // Load background from SD
- M5.Lcd.drawJpg(tetris_img, 34215); // Load background from file data
- PutStartPos(); // Start Position
- for (int i = 0; i < 4; ++i)
- screen[pos.X + block.square[rot][i].X][pos.Y + block.square[rot][i].Y] =
- block.color;
- Draw(); // Draw block
- }
- //========================================================================
- void loop() {
- if (gameover) return;
- Point next_pos;
- int next_rot = rot;
- GetNextPosRot(&next_pos, &next_rot);
- ReviseScreen(next_pos, next_rot);
- M5.update();
- delay(game_speed); // SPEED ADJUST
- }
- //========================================================================
- void Draw() { // Draw 120x240 in the center
- for (int i = 0; i < Width; ++i)
- for (int j = 0; j < Height; ++j)
- for (int k = 0; k < Length; ++k)
- for (int l = 0; l < Length; ++l)
- backBuffer[j * Length + l][i * Length + k] =
- BlockImage[screen[i][j]][k][l];
- M5.Lcd.drawBitmap(100, 0, 120, 240, (uint8_t*)backBuffer);
- }
- //========================================================================
- void PutStartPos() {
- pos.X = 4;
- pos.Y = 1;
- block = blocks[random(7)];
- rot = random(block.numRotate);
- }
- //========================================================================
- bool GetSquares(Block block, Point pos, int rot, Point* squares) {
- bool overlap = false;
- for (int i = 0; i < 4; ++i) {
- Point p;
- p.X = pos.X + block.square[rot][i].X;
- p.Y = pos.Y + block.square[rot][i].Y;
- overlap |= p.X < 0 || p.X >= Width || p.Y < 0 || p.Y >= Height ||
- screen[p.X][p.Y] != 0;
- squares[i] = p;
- }
- return !overlap;
- }
- //========================================================================
- void GameOver() {
- for (int i = 0; i < Width; ++i)
- for (int j = 0; j < Height; ++j)
- if (screen[i][j] != 0) screen[i][j] = 4;
- gameover = true;
- }
- //========================================================================
- void ClearKeys() {
- but_A = false;
- but_LEFT = false;
- but_RIGHT = false;
- }
- //========================================================================
- bool KeyPadLoop() {
- if (M5.BtnA.wasPressed()) {
- ClearKeys();
- but_LEFT = true;
- return true;
- }
- if (M5.BtnB.wasPressed()) {
- ClearKeys();
- but_RIGHT = true;
- return true;
- }
- if (M5.BtnC.wasPressed()) {
- ClearKeys();
- but_A = true;
- return true;
- }
- return false;
- }
- //========================================================================
- void GetNextPosRot(Point* pnext_pos, int* pnext_rot) {
- bool received = KeyPadLoop();
- if (but_A) started = true;
- if (!started) return;
- pnext_pos->X = pos.X;
- pnext_pos->Y = pos.Y;
- if ((fall_cnt = (fall_cnt + 1) % 10) == 0)
- pnext_pos->Y += 1;
- else if (received) {
- if (but_LEFT) {
- but_LEFT = false;
- pnext_pos->X -= 1;
- } else if (but_RIGHT) {
- but_RIGHT = false;
- pnext_pos->X += 1;
- } else if (but_A) {
- but_A = false;
- *pnext_rot = (*pnext_rot + block.numRotate - 1) % block.numRotate;
- }
- }
- }
- //========================================================================
- void DeleteLine() {
- for (int j = 0; j < Height; ++j) {
- bool Delete = true;
- for (int i = 0; i < Width; ++i)
- if (screen[i][j] == 0) Delete = false;
- if (Delete)
- for (int k = j; k >= 1; --k)
- for (int i = 0; i < Width; ++i) screen[i][k] = screen[i][k - 1];
- }
- }
- //========================================================================
- void ReviseScreen(Point next_pos, int next_rot) {
- if (!started) return;
- Point next_squares[4];
- for (int i = 0; i < 4; ++i)
- screen[pos.X + block.square[rot][i].X][pos.Y + block.square[rot][i].Y] =
- 0;
- if (GetSquares(block, next_pos, next_rot, next_squares)) {
- for (int i = 0; i < 4; ++i) {
- screen[next_squares[i].X][next_squares[i].Y] = block.color;
- }
- pos = next_pos;
- rot = next_rot;
- } else {
- for (int i = 0; i < 4; ++i)
- screen[pos.X + block.square[rot][i].X]
- [pos.Y + block.square[rot][i].Y] = block.color;
- if (next_pos.Y == pos.Y + 1) {
- DeleteLine();
- PutStartPos();
- if (!GetSquares(block, pos, rot, next_squares)) {
- for (int i = 0; i < 4; ++i)
- screen[pos.X + block.square[rot][i].X]
- [pos.Y + block.square[rot][i].Y] = block.color;
- GameOver();
- }
- }
- }
- Draw();
- }
- //========================================================================
- void make_block(int n, uint16_t color) { // Make Block color
- for (int i = 0; i < 12; i++)
- for (int j = 0; j < 12; j++) {
- BlockImage[n][i][j] = color; // Block color
- if (i == 0 || j == 0) BlockImage[n][i][j] = 0; // BLACK Line
- }
- }
- //========================================================================
|