From bd05d2380027d908a5adc96111d33711200e351b Mon Sep 17 00:00:00 2001 From: Dan Frumin Date: Sun, 1 Sep 2019 18:31:04 +0200 Subject: [PATCH] restructure code and add simple collision detection --- Makefile | 4 ++ tetris.ino | 181 ++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 133 insertions(+), 52 deletions(-) diff --git a/Makefile b/Makefile index d0c2c36..240ea00 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,10 @@ CTAGS_CMD = $(CTAGS_PATH) -auef TAGS_FILE = TAGS all: + $(ARDUINO) --verify tetris.ino + + +upload: $(ARDUINO) --upload tetris.ino diff --git a/tetris.ino b/tetris.ino index 568edd4..277e2c0 100644 --- a/tetris.ino +++ b/tetris.ino @@ -2,42 +2,53 @@ #include #include -TFT_eSPI tft = TFT_eSPI(); // Invoke custom library -// pins are defined un User_Setup.h +// We assume the size of the screen 120x160 +#define GRID_WIDTH 12 +#define GRID_HEIGHT 16 +#define BLOCK_SIZE 10 +#define BLOCK_MARGIN 2 const int BTN1_PIN = 25; volatile bool btn1_pressed = false; const int BTN2_PIN = 33; volatile bool btn2_pressed = false; +// I am using ST7735S, a very cheap display from aliexpress +TFT_eSPI tft = TFT_eSPI(); +// pins are defined un User_Setup.h + + // forward declarations void IRAM_ATTR isr1(); void IRAM_ATTR isr2(); -void setup() { - tft.init(); // initialize a ST7735S chip - - // set up the buttons and the interrupts - pinMode(BTN1_PIN, INPUT_PULLUP); - attachInterrupt(BTN1_PIN, isr1, FALLING); - pinMode(BTN2_PIN, INPUT_PULLUP); - attachInterrupt(BTN2_PIN, isr2, FALLING); - - init_board(); - - delay(100); -} - -#define GRID_WIDTH 12 -#define GRID_HEIGHT 18 -#define BLOCK_SIZE 10 -#define BLOCK_MARGIN 2 - -#define BLOCK_WIDTH 20 -#define BLOCK_HEIGHT 30 - +// the main board and the offboard, to check for dirty squares uint32_t main_board[GRID_WIDTH][GRID_HEIGHT], offboard[GRID_WIDTH][GRID_HEIGHT]; +/* + The value (i,j) on the board is given by main_board[i][j]. + if board(i,j) = 0, then the space there is empty + otherwise board(i,j)'s first bit determines whether the block is "old" or not, and the rest denotes a color + */ + +/* Blocks are defined in grids of 4x4: + + 0 1 2 3 + 4 5 6 7 + 8 9 10 11 + 12 13 14 15 + +*/ +#define BLOCKS_COUNT 2 +uint8_t blocks[BLOCKS_COUNT][4] = + { + {0,1,2,3},{0,1,4,5} + }; + +#define COLORS_SIZE 6 +uint32_t block_colors[COLORS_SIZE] = { TFT_NAVY, TFT_DARKGREEN, TFT_RED, TFT_YELLOW, TFT_GREEN, TFT_PINK }; + +// Graphics-related functions void init_board() { @@ -48,7 +59,18 @@ init_board() { main_board[i][j] = 0; offboard[i][j] = 0; - } + } +} + +void +set_board(int i, int j, int color, bool old) +{ + int v = color<<1; + if (old) + { + v = v|1; + } + main_board[i][j] = v; } void @@ -59,43 +81,108 @@ draw_board() { if (main_board[i][j] == offboard[i][j]) continue; // no need to redraw offboard[i][j] = main_board[i][j]; + int color = main_board[i][j]>>1; tft.fillRect(i*BLOCK_SIZE+BLOCK_MARGIN,j*BLOCK_SIZE+BLOCK_MARGIN, BLOCK_SIZE-BLOCK_MARGIN,BLOCK_SIZE-BLOCK_MARGIN, - main_board[i][j]); + color); } } -uint8_t blocks[2][4] = - { - {0,1,2,3},{0,1,4,5} - }; - - // Draw a block of type TYPE with color COLOR, starting at coordinates X, Y. // Updates the main_board directly void -draw_block(int x, int y, int type, int color) +draw_block(int x, int y, int type, int color, bool old) { for (int i = 0; i < 4; i++) { int v = blocks[type][i]; int dx = v%4; int dy = v/4; - main_board[x+dx][y+dy] = color; + set_board(x+dx, y+dy, color, old); } } + +// Game logic + +// Current and previous positions of the active block int px = 0, cx = 0; int py = 0, cy = 0; +// Type of the active block. Should be 0 <= cblokc_ty < BLOCKS_COUNT int cblock_ty = 0; +// Color of the current block +int cblock_color = TFT_RED; + +void +new_block() +{ + px = 0; cx = 0; + py = 0; cy = 0; + cblock_ty = 0; + cblock_color = TFT_RED; +} + +bool +check_collision() +{ + for (int i = 0; i < 4; i++) + { + int v = blocks[cblock_ty][i]; + int dx = v%4; + int dy = v/4; + if (cy+dy >= GRID_HEIGHT) + { + return true; + } + int is_old = main_board[cx+dx][cy+dy]&1; + if (is_old) + { + return true; + } + } + + return false; +} + +// Setup +void setup() { + tft.init(); // initialize a ST7735S chip + + Serial.begin(115200); + + // set up the buttons and the interrupts + pinMode(BTN1_PIN, INPUT_PULLUP); + attachInterrupt(BTN1_PIN, isr1, FALLING); + pinMode(BTN2_PIN, INPUT_PULLUP); + attachInterrupt(BTN2_PIN, isr2, FALLING); + + init_board(); + new_block(); + + delay(100); +} + void loop() { - // if (dy == 0) { - // dx = map(esp_random(), 0, 0xFFFFFFFF, 0, 128/5); - // } - cy++; - if (cy >= GRID_HEIGHT) { - cy = 0; - } + + if (check_collision ()) + { + // designate the block as "old" and leave it there + draw_block(px, py, cblock_ty, cblock_color, true); + new_block(); + return; + } + + // clear the previous block + if (cy != py || cx != px) + { + draw_block(px, py, cblock_ty, TFT_BLACK, false); + } + draw_block(cx, cy, cblock_ty, cblock_color, false); + + draw_board(); + + px = cx; + py = cy; if (btn1_pressed) { @@ -108,19 +195,9 @@ void loop() { cx++; } - // clear the previous block - if (cy != py || cx != px) - { - draw_block(px, py, cblock_ty, TFT_BLACK); - } - draw_block(cx, cy, cblock_ty, TFT_RED); - - draw_board(); + cy++; delay(350); - - px = cx; - py = cy; } void IRAM_ATTR