Tetris.ino 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  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 {
  17. int X, Y;
  18. };
  19. struct Block {
  20. Point square[4][4];
  21. int numRotate, color;
  22. };
  23. Point pos;
  24. Block block;
  25. int rot, fall_cnt = 0;
  26. bool started = false, gameover = false;
  27. boolean but_A = false, but_LEFT = false, but_RIGHT = false;
  28. int game_speed = 25; // 25msec
  29. Block blocks[7] = {{{{{-1, 0}, {0, 0}, {1, 0}, {2, 0}},
  30. {{0, -1}, {0, 0}, {0, 1}, {0, 2}},
  31. {{0, 0}, {0, 0}, {0, 0}, {0, 0}},
  32. {{0, 0}, {0, 0}, {0, 0}, {0, 0}}},
  33. 2,
  34. 1},
  35. {{{{0, -1}, {1, -1}, {0, 0}, {1, 0}},
  36. {{0, 0}, {0, 0}, {0, 0}, {0, 0}},
  37. {{0, 0}, {0, 0}, {0, 0}, {0, 0}},
  38. {{0, 0}, {0, 0}, {0, 0}, {0, 0}}},
  39. 1,
  40. 2},
  41. {{{{-1, -1}, {-1, 0}, {0, 0}, {1, 0}},
  42. {{-1, 1}, {0, 1}, {0, 0}, {0, -1}},
  43. {{-1, 0}, {0, 0}, {1, 0}, {1, 1}},
  44. {{1, -1}, {0, -1}, {0, 0}, {0, 1}}},
  45. 4,
  46. 3},
  47. {{{{-1, 0}, {0, 0}, {0, 1}, {1, 1}},
  48. {{0, -1}, {0, 0}, {-1, 0}, {-1, 1}},
  49. {{0, 0}, {0, 0}, {0, 0}, {0, 0}},
  50. {{0, 0}, {0, 0}, {0, 0}, {0, 0}}},
  51. 2,
  52. 4},
  53. {{{{-1, 0}, {0, 0}, {1, 0}, {1, -1}},
  54. {{-1, -1}, {0, -1}, {0, 0}, {0, 1}},
  55. {{-1, 1}, {-1, 0}, {0, 0}, {1, 0}},
  56. {{0, -1}, {0, 0}, {0, 1}, {1, 1}}},
  57. 4,
  58. 5},
  59. {{{{-1, 1}, {0, 1}, {0, 0}, {1, 0}},
  60. {{0, -1}, {0, 0}, {1, 0}, {1, 1}},
  61. {{0, 0}, {0, 0}, {0, 0}, {0, 0}},
  62. {{0, 0}, {0, 0}, {0, 0}, {0, 0}}},
  63. 2,
  64. 6},
  65. {{{{-1, 0}, {0, 0}, {1, 0}, {0, -1}},
  66. {{0, -1}, {0, 0}, {0, 1}, {-1, 0}},
  67. {{-1, 0}, {0, 0}, {1, 0}, {0, 1}},
  68. {{0, -1}, {0, 0}, {0, 1}, {1, 0}}},
  69. 4,
  70. 7}};
  71. extern uint8_t tetris_img[];
  72. //========================================================================
  73. void setup(void) {
  74. M5.begin(); // M5STACK INITIALIZE
  75. M5.Power.begin();
  76. M5.Lcd.setBrightness(200); // BRIGHTNESS = MAX 255
  77. M5.Lcd.fillScreen(BLACK); // CLEAR SCREEN
  78. //----------------------------// Make Block ----------------------------
  79. make_block(0, BLACK); // Type No, Color
  80. make_block(1, 0x00F0); // DDDD RED
  81. make_block(2, 0xFBE4); // DD,DD PUPLE
  82. make_block(3, 0xFF00); // D__,DDD BLUE
  83. make_block(4, 0xFF87); // DD_,_DD GREEN
  84. make_block(5, 0x87FF); // __D,DDD YELLO
  85. make_block(6, 0xF00F); // _DD,DD_ LIGHT GREEN
  86. make_block(7, 0xF8FC); // _D_,DDD PINK
  87. //----------------------------------------------------------------------
  88. // M5.Lcd.drawJpgFile(SD, "/tetris.jpg"); // Load background from SD
  89. M5.Lcd.drawJpg(tetris_img, 34215); // Load background from file data
  90. PutStartPos(); // Start Position
  91. for (int i = 0; i < 4; ++i)
  92. screen[pos.X + block.square[rot][i].X][pos.Y + block.square[rot][i].Y] =
  93. block.color;
  94. Draw(); // Draw block
  95. }
  96. //========================================================================
  97. void loop() {
  98. if (gameover) return;
  99. Point next_pos;
  100. int next_rot = rot;
  101. GetNextPosRot(&next_pos, &next_rot);
  102. ReviseScreen(next_pos, next_rot);
  103. M5.update();
  104. delay(game_speed); // SPEED ADJUST
  105. }
  106. //========================================================================
  107. void Draw() { // Draw 120x240 in the center
  108. for (int i = 0; i < Width; ++i)
  109. for (int j = 0; j < Height; ++j)
  110. for (int k = 0; k < Length; ++k)
  111. for (int l = 0; l < Length; ++l)
  112. backBuffer[j * Length + l][i * Length + k] =
  113. BlockImage[screen[i][j]][k][l];
  114. M5.Lcd.drawBitmap(100, 0, 120, 240, (uint8_t*)backBuffer);
  115. }
  116. //========================================================================
  117. void PutStartPos() {
  118. pos.X = 4;
  119. pos.Y = 1;
  120. block = blocks[random(7)];
  121. rot = random(block.numRotate);
  122. }
  123. //========================================================================
  124. bool GetSquares(Block block, Point pos, int rot, Point* squares) {
  125. bool overlap = false;
  126. for (int i = 0; i < 4; ++i) {
  127. Point p;
  128. p.X = pos.X + block.square[rot][i].X;
  129. p.Y = pos.Y + block.square[rot][i].Y;
  130. overlap |= p.X < 0 || p.X >= Width || p.Y < 0 || p.Y >= Height ||
  131. screen[p.X][p.Y] != 0;
  132. squares[i] = p;
  133. }
  134. return !overlap;
  135. }
  136. //========================================================================
  137. void GameOver() {
  138. for (int i = 0; i < Width; ++i)
  139. for (int j = 0; j < Height; ++j)
  140. if (screen[i][j] != 0) screen[i][j] = 4;
  141. gameover = true;
  142. }
  143. //========================================================================
  144. void ClearKeys() {
  145. but_A = false;
  146. but_LEFT = false;
  147. but_RIGHT = false;
  148. }
  149. //========================================================================
  150. bool KeyPadLoop() {
  151. if (M5.BtnA.wasPressed()) {
  152. ClearKeys();
  153. but_LEFT = true;
  154. return true;
  155. }
  156. if (M5.BtnB.wasPressed()) {
  157. ClearKeys();
  158. but_RIGHT = true;
  159. return true;
  160. }
  161. if (M5.BtnC.wasPressed()) {
  162. ClearKeys();
  163. but_A = true;
  164. return true;
  165. }
  166. return false;
  167. }
  168. //========================================================================
  169. void GetNextPosRot(Point* pnext_pos, int* pnext_rot) {
  170. bool received = KeyPadLoop();
  171. if (but_A) started = true;
  172. if (!started) return;
  173. pnext_pos->X = pos.X;
  174. pnext_pos->Y = pos.Y;
  175. if ((fall_cnt = (fall_cnt + 1) % 10) == 0)
  176. pnext_pos->Y += 1;
  177. else if (received) {
  178. if (but_LEFT) {
  179. but_LEFT = false;
  180. pnext_pos->X -= 1;
  181. } else if (but_RIGHT) {
  182. but_RIGHT = false;
  183. pnext_pos->X += 1;
  184. } else if (but_A) {
  185. but_A = false;
  186. *pnext_rot = (*pnext_rot + block.numRotate - 1) % block.numRotate;
  187. }
  188. }
  189. }
  190. //========================================================================
  191. void DeleteLine() {
  192. for (int j = 0; j < Height; ++j) {
  193. bool Delete = true;
  194. for (int i = 0; i < Width; ++i)
  195. if (screen[i][j] == 0) Delete = false;
  196. if (Delete)
  197. for (int k = j; k >= 1; --k)
  198. for (int i = 0; i < Width; ++i) screen[i][k] = screen[i][k - 1];
  199. }
  200. }
  201. //========================================================================
  202. void ReviseScreen(Point next_pos, int next_rot) {
  203. if (!started) return;
  204. Point next_squares[4];
  205. for (int i = 0; i < 4; ++i)
  206. screen[pos.X + block.square[rot][i].X][pos.Y + block.square[rot][i].Y] =
  207. 0;
  208. if (GetSquares(block, next_pos, next_rot, next_squares)) {
  209. for (int i = 0; i < 4; ++i) {
  210. screen[next_squares[i].X][next_squares[i].Y] = block.color;
  211. }
  212. pos = next_pos;
  213. rot = next_rot;
  214. } else {
  215. for (int i = 0; i < 4; ++i)
  216. screen[pos.X + block.square[rot][i].X]
  217. [pos.Y + block.square[rot][i].Y] = block.color;
  218. if (next_pos.Y == pos.Y + 1) {
  219. DeleteLine();
  220. PutStartPos();
  221. if (!GetSquares(block, pos, rot, next_squares)) {
  222. for (int i = 0; i < 4; ++i)
  223. screen[pos.X + block.square[rot][i].X]
  224. [pos.Y + block.square[rot][i].Y] = block.color;
  225. GameOver();
  226. }
  227. }
  228. }
  229. Draw();
  230. }
  231. //========================================================================
  232. void make_block(int n, uint16_t color) { // Make Block color
  233. for (int i = 0; i < 12; i++)
  234. for (int j = 0; j < 12; j++) {
  235. BlockImage[n][i][j] = color; // Block color
  236. if (i == 0 || j == 0) BlockImage[n][i][j] = 0; // BLACK Line
  237. }
  238. }
  239. //========================================================================