Tetris.ino 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. //========================================================================
  2. // TETRIS with M5STACK : 2018.01.20 Transplant by macsbug
  3. // Controller : Buttons A = LEFT, B = RIGHT, C = START, ROTATE
  4. // Display : Left = 100x240, Center = 120x240, Right = 100x240
  5. // Block : 8ea, 12x12 pixel
  6. // SD : tetris.jpg : BackGround Image : R.G.B 320x240 pixel
  7. // Github : https://macsbug.wordpress.com/2018/01/20/tetris-with-m5stack/
  8. //========================================================================
  9. #include <M5Stack.h> // M5STACK
  10. uint16_t BlockImage[8][12][12]; // Block
  11. uint16_t backBuffer[240][120]; // GAME AREA
  12. const int Length = 12; // the number of pixels for a side of a block
  13. const int Width = 10; // the number of horizontal blocks
  14. const int Height = 20; // the number of vertical blocks
  15. int screen[Width][Height] = {0}; //it shows color-numbers of all positions
  16. struct Point {int X, Y;};
  17. struct Block {Point square[4][4]; int numRotate, color;};
  18. Point pos; Block block;
  19. int rot, fall_cnt = 0;
  20. bool started = false, gameover = false;
  21. boolean but_A = false, but_LEFT = false, but_RIGHT = false;
  22. int game_speed = 25; // 25msec
  23. Block blocks[7] = {
  24. {{{{-1,0},{0,0},{1,0},{2,0}},{{0,-1},{0,0},{0,1},{0,2}},
  25. {{0,0},{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0},{0,0}}},2,1},
  26. {{{{0,-1},{1,-1},{0,0},{1,0}},{{0,0},{0,0},{0,0},{0,0}},
  27. {{0,0},{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0},{0,0}}},1,2},
  28. {{{{-1,-1},{-1,0},{0,0},{1,0}},{{-1,1},{0,1},{0,0},{0,-1}},
  29. {{-1,0},{0,0},{1,0},{1,1}},{{1,-1},{0,-1},{0,0},{0,1}}},4,3},
  30. {{{{-1,0},{0,0},{0,1},{1,1}},{{0,-1},{0,0},{-1,0},{-1,1}},
  31. {{0,0},{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0},{0,0}}},2,4},
  32. {{{{-1,0},{0,0},{1,0},{1,-1}},{{-1,-1},{0,-1},{0,0},{0,1}},
  33. {{-1,1},{-1,0},{0,0},{1,0}},{{0,-1},{0,0},{0,1},{1,1}}},4,5},
  34. {{{{-1,1},{0,1},{0,0},{1,0}},{{0,-1},{0,0},{1,0},{1,1}},
  35. {{0,0},{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0},{0,0}}},2,6},
  36. {{{{-1,0},{0,0},{1,0},{0,-1}},{{0,-1},{0,0},{0,1},{-1,0}},
  37. {{-1,0},{0,0},{1,0},{0,1}},{{0,-1},{0,0},{0,1},{1,0}}},4,7}
  38. };
  39. extern uint8_t tetris_img[];
  40. //========================================================================
  41. void setup(void) {
  42. M5.begin(); // M5STACK INITIALIZE
  43. M5.Power.begin();
  44. M5.Lcd.setBrightness(200); // BRIGHTNESS = MAX 255
  45. M5.Lcd.fillScreen(BLACK); // CLEAR SCREEN
  46. //----------------------------// Make Block ----------------------------
  47. make_block( 0, BLACK); // Type No, Color
  48. make_block( 1, 0x00F0); // DDDD RED
  49. make_block( 2, 0xFBE4); // DD,DD PUPLE
  50. make_block( 3, 0xFF00); // D__,DDD BLUE
  51. make_block( 4, 0xFF87); // DD_,_DD GREEN
  52. make_block( 5, 0x87FF); // __D,DDD YELLO
  53. make_block( 6, 0xF00F); // _DD,DD_ LIGHT GREEN
  54. make_block( 7, 0xF8FC); // _D_,DDD PINK
  55. //----------------------------------------------------------------------
  56. // M5.Lcd.drawJpgFile(SD, "/tetris.jpg"); // Load background from SD
  57. M5.Lcd.drawJpg(tetris_img, 34215); // Load background from file data
  58. PutStartPos(); // Start Position
  59. for (int i = 0; i < 4; ++i) screen[pos.X +
  60. block.square[rot][i].X][pos.Y + block.square[rot][i].Y] = block.color;
  61. Draw(); // Draw block
  62. }
  63. //========================================================================
  64. void loop() {
  65. if (gameover) return;
  66. Point next_pos;
  67. int next_rot = rot;
  68. GetNextPosRot(&next_pos, &next_rot);
  69. ReviseScreen(next_pos, next_rot);
  70. M5.update();
  71. delay(game_speed); // SPEED ADJUST
  72. }
  73. //========================================================================
  74. void Draw() { // Draw 120x240 in the center
  75. for (int i = 0; i < Width; ++i) for (int j = 0; j < Height; ++j)
  76. for (int k = 0; k < Length; ++k) for (int l = 0; l < Length; ++l)
  77. backBuffer[j * Length + l][i * Length + k] = BlockImage[screen[i][j]][k][l];
  78. M5.Lcd.drawBitmap(100, 0, 120, 240, (uint8_t*)backBuffer);
  79. }
  80. //========================================================================
  81. void PutStartPos() {
  82. pos.X = 4; pos.Y = 1;
  83. block = blocks[random(7)];
  84. rot = random(block.numRotate);
  85. }
  86. //========================================================================
  87. bool GetSquares(Block block, Point pos, int rot, Point* squares) {
  88. bool overlap = false;
  89. for (int i = 0; i < 4; ++i) {
  90. Point p;
  91. p.X = pos.X + block.square[rot][i].X;
  92. p.Y = pos.Y + block.square[rot][i].Y;
  93. overlap |= p.X < 0 || p.X >= Width || p.Y < 0 || p.Y >=
  94. Height || screen[p.X][p.Y] != 0;
  95. squares[i] = p;
  96. }
  97. return !overlap;
  98. }
  99. //========================================================================
  100. void GameOver() {
  101. for (int i = 0; i < Width; ++i) for (int j = 0; j < Height; ++j)
  102. if (screen[i][j] != 0) screen[i][j] = 4;
  103. gameover = true;
  104. }
  105. //========================================================================
  106. void ClearKeys() { but_A=false; but_LEFT=false; but_RIGHT=false;}
  107. //========================================================================
  108. bool KeyPadLoop(){
  109. if(M5.BtnA.wasPressed()){ClearKeys();but_LEFT =true;return true;}
  110. if(M5.BtnB.wasPressed()){ClearKeys();but_RIGHT=true;return true;}
  111. if(M5.BtnC.wasPressed()){ClearKeys();but_A =true;return true;}
  112. return false;
  113. }
  114. //========================================================================
  115. void GetNextPosRot(Point* pnext_pos, int* pnext_rot) {
  116. bool received = KeyPadLoop();
  117. if (but_A) started = true;
  118. if (!started) return;
  119. pnext_pos->X = pos.X;
  120. pnext_pos->Y = pos.Y;
  121. if ((fall_cnt = (fall_cnt + 1) % 10) == 0) pnext_pos->Y += 1;
  122. else if (received) {
  123. if (but_LEFT) { but_LEFT = false; pnext_pos->X -= 1;}
  124. else if (but_RIGHT) { but_RIGHT = false; pnext_pos->X += 1;}
  125. else if (but_A) { but_A = false;
  126. *pnext_rot = (*pnext_rot + block.numRotate - 1)%block.numRotate;
  127. }
  128. }
  129. }
  130. //========================================================================
  131. void DeleteLine() {
  132. for (int j = 0; j < Height; ++j) {
  133. bool Delete = true;
  134. for (int i = 0; i < Width; ++i) if (screen[i][j] == 0) Delete = false;
  135. if (Delete) for (int k = j; k >= 1; --k)
  136. for (int i = 0; i < Width; ++i) screen[i][k] = screen[i][k - 1];
  137. }
  138. }
  139. //========================================================================
  140. void ReviseScreen(Point next_pos, int next_rot) {
  141. if (!started) return;
  142. Point next_squares[4];
  143. for (int i = 0; i < 4; ++i) screen[pos.X +
  144. block.square[rot][i].X][pos.Y + block.square[rot][i].Y] = 0;
  145. if (GetSquares(block, next_pos, next_rot, next_squares)) {
  146. for (int i = 0; i < 4; ++i){
  147. screen[next_squares[i].X][next_squares[i].Y] = block.color;
  148. }
  149. pos = next_pos; rot = next_rot;
  150. }
  151. else {
  152. for (int i = 0; i < 4; ++i) screen[pos.X +
  153. block.square[rot][i].X][pos.Y + block.square[rot][i].Y] = block.color;
  154. if (next_pos.Y == pos.Y + 1) {
  155. DeleteLine(); PutStartPos();
  156. if (!GetSquares(block, pos, rot, next_squares)) {
  157. for (int i = 0; i < 4; ++i) screen[pos.X +
  158. block.square[rot][i].X][pos.Y + block.square[rot][i].Y] = block.color;
  159. GameOver();
  160. }
  161. }
  162. }
  163. Draw();
  164. }
  165. //========================================================================
  166. void make_block( int n , uint16_t color ){ // Make Block color
  167. for ( int i =0 ; i < 12; i++ ) for ( int j =0 ; j < 12; j++ ){
  168. BlockImage[n][i][j] = color; // Block color
  169. if ( i == 0 || j == 0 ) BlockImage[n][i][j] = 0; // BLACK Line
  170. }
  171. }
  172. //========================================================================