#include <Adafruit_NeoPixel.h> //Downlaod here: https://electronoobs.com/eng_arduino_Adafruit_NeoPixel.php
//------------------------------------------------------------------------------------------------------------------
//-------------------------------------BASIC-DEFINES----------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------
// size of the LED grid
#define GRID_W (10)
#define GRID_H (16)
#define STRAND_LENGTH (GRID_W*GRID_H)
#define LED_DATA_PIN (23)
#define PIECE_W (4)
#define PIECE_H (4)
#define NUM_PIECE_TYPES (7)
// gravity options
#define DROP_MINIMUM (25) // top speed gravity can reach
#define DROP_ACCELERATION (20) // how fast gravity increases
#define INITIAL_MOVE_DELAY (100)
#define INITIAL_DROP_DELAY (500)
#define INITIAL_DRAW_DELAY (30)
#define BUTTON_DELAY (50)
//------------------------------------------------------------------------------------------------------------------
//-------------------------------------PIECES-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------
// 1 color drawings of each piece in each rotation.
// Each piece is max 4 wide, 4 tall, and 4 rotations.
const char piece_I[] = {
0,0,0,0,
1,1,1,1,
0,0,0,0,
0,0,0,0,
0,0,1,0,
0,0,1,0,
0,0,1,0,
0,0,1,0,
0,0,0,0,
0,0,0,0,
1,1,1,1,
0,0,0,0,
0,1,0,0,
0,1,0,0,
0,1,0,0,
0,1,0,0,
};
const char piece_L[] = {
0,0,1,0,
1,1,1,0,
0,0,0,0,
0,0,0,0,
0,1,0,0,
0,1,0,0,
0,1,1,0,
0,0,0,0,
0,0,0,0,
1,1,1,0,
1,0,0,0,
0,0,0,0,
1,1,0,0,
0,1,0,0,
0,1,0,0,
0,0,0,0,
};
const char piece_J[] = {
1,0,0,0,
1,1,1,0,
0,0,0,0,
0,0,0,0,
0,1,1,0,
0,1,0,0,
0,1,0,0,
0,0,0,0,
0,0,0,0,
1,1,1,0,
0,0,1,0,
0,0,0,0,
0,1,0,0,
0,1,0,0,
1,1,0,0,
0,0,0,0,
};
const char piece_T[] = {
0,1,0,0,
1,1,1,0,
0,0,0,0,
0,0,0,0,
0,1,0,0,
0,1,1,0,
0,1,0,0,
0,0,0,0,
0,0,0,0,
1,1,1,0,
0,1,0,0,
0,0,0,0,
0,1,0,0,
1,1,0,0,
0,1,0,0,
0,0,0,0,
};
const char piece_S[] = {
0,1,1,0,
1,1,0,0,
0,0,0,0,
0,0,0,0,
0,1,0,0,
0,1,1,0,
0,0,1,0,
0,0,0,0,
0,0,0,0,
0,1,1,0,
1,1,0,0,
0,0,0,0,
1,0,0,0,
1,1,0,0,
0,1,0,0,
0,0,0,0,
};
const char piece_Z[] = {
1,1,0,0,
0,1,1,0,
0,0,0,0,
0,0,0,0,
0,0,1,0,
0,1,1,0,
0,1,0,0,
0,0,0,0,
0,0,0,0,
1,1,0,0,
0,1,1,0,
0,0,0,0,
0,1,0,0,
1,1,0,0,
1,0,0,0,
0,0,0,0,
};
const char piece_O[] = {
1,1,0,0,
1,1,0,0,
0,0,0,0,
0,0,0,0,
1,1,0,0,
1,1,0,0,
0,0,0,0,
0,0,0,0,
1,1,0,0,
1,1,0,0,
0,0,0,0,
0,0,0,0,
1,1,0,0,
1,1,0,0,
0,0,0,0,
0,0,0,0,
};
// An array of pointers!
const char *pieces[NUM_PIECE_TYPES] = {
piece_S,
piece_Z,
piece_L,
piece_J,
piece_O,
piece_T,
piece_I,
};
const long piece_colors[NUM_PIECE_TYPES] = {
0x990000, // green S
0x00FF00, // red Z
0x80FF00, // orange L
0x000044, // blue J
0xFFFF00, // yellow O
0x00FFFF, // purple T
0xFF00FF, // cyan I
};
//------------------------------------------------------------------------------------------------------------------
//-------------------------------------PICTURE-STRUCTS--------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------
struct {
int grid_pos[53] = {20, 21, 22, 23, 24, 25, 26, 28, 30, 32, 33, 35, 36, 38, 40, 41, 42, 43, 44, 45, 46, 48, 50, 53, 55, 56, 58, 60, 63, 65, 66, 67, 68, 93, 94, 95, 96, 97, 98, 103, 106, 114, 116, 117, 118, 125, 126, 133, 134, 135, 136, 137, 138};
int led_pos[53] = {13, 18, 45, 50, 77, 82, 109, 141, 12, 44, 51, 83, 108, 140, 11, 20, 43, 52, 75, 84, 107, 139, 10, 53, 85, 106, 138, 9, 54, 86, 105, 118, 137, 57, 70, 89, 102, 121, 134, 58, 101, 68, 100, 123, 132, 92, 99, 61, 66, 93, 98, 125, 130};
long col[53] = {0xff0000, 0xff0000, 0xff0000, 0xff9900, 0xff9900, 0xff9900, 0xffff00, 0xffff00, 0xff0000, 0xff0000, 0xff9900, 0xff9900, 0xffff00, 0xffff00, 0xff0000, 0xff0000, 0xff0000, 0xff9900, 0xff9900, 0xff9900, 0xffff00, 0xffff00, 0xff0000, 0xff9900, 0xff9900, 0xffff00, 0xffff00, 0xff0000, 0xff9900, 0xff9900, 0xffff00, 0xffff00, 0xffff00, 0x6aa84f, 0x6aa84f, 0x6aa84f, 0x6fa8dc, 0x6fa8dc, 0x6fa8dc, 0x6aa84f, 0x6fa8dc, 0x6aa84f, 0x6fa8dc, 0x6fa8dc, 0x6fa8dc, 0x6aa84f, 0x6fa8dc, 0x6aa84f, 0x6aa84f, 0x6aa84f, 0x6fa8dc, 0x6fa8dc, 0x6fa8dc};
int led_num = 53;
} (p_pause);
struct {
int grid_pos[51] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 23, 27, 31, 33, 34, 35, 37, 41, 43, 47, 51, 53, 54, 55, 57, 71, 72, 73, 75, 77, 78, 79, 81, 83, 85, 87, 91, 92, 93, 95, 98, 101, 102, 105, 109, 111, 113, 115, 117, 118, 119};
int led_pos[51] = {14, 17, 46, 49, 78, 81, 110, 113, 142, 18, 50, 114, 19, 51, 76, 83, 115, 20, 52, 116, 21, 53, 74, 85, 117, 23, 40, 55, 87, 119, 136, 151, 24, 56, 88, 120, 25, 38, 57, 89, 134, 26, 37, 90, 154, 27, 59, 91, 123, 132, 155};
long col[51] = {0xea4335, 0xea4335, 0xea4335, 0xff9900, 0xff9900, 0xff9900, 0xffff00, 0xffff00, 0xffff00, 0xea4335, 0xff9900, 0xffff00, 0xea4335, 0xff9900, 0xf6b26b, 0xf6b26b, 0xffff00, 0xea4335, 0xff9900, 0xffff00, 0xff0000, 0xff9900, 0xff9900, 0xff9900, 0xffff00, 0x00ff00, 0x00ff00, 0x00ff00, 0x00ffff, 0xff00ff, 0xff00ff, 0xff00ff, 0x00ff00, 0x00ff00, 0x00ffff, 0xff00ff, 0x00ff00, 0x00ff00, 0x00ff00, 0x00ffff, 0xff00ff, 0x00ff00, 0x00ff00, 0x00ffff, 0xff00ff, 0x00ff00, 0x00ff00, 0x00ffff, 0xff00ff, 0xff00ff, 0xff00ff};
int led_num = 51;
} (p_tetris);
struct {
int grid_pos[58] = {20, 21, 22, 23, 25, 26, 27, 28, 30, 35, 38, 40, 45, 48, 50, 52, 53, 55, 56, 57, 58, 60, 63, 65, 68, 70, 71, 72, 73, 75, 78, 91, 95, 97, 98, 99, 101, 102, 104, 105, 107, 111, 113, 115, 117, 121, 125, 127, 128, 129, 131, 135, 137, 141, 145, 147, 148, 149};
int led_pos[58] = {13, 18, 45, 50, 82, 109, 114, 141, 12, 83, 140, 11, 84, 139, 10, 42, 53, 85, 106, 117, 138, 9, 54, 86, 137, 8, 23, 40, 55, 87, 136, 25, 89, 121, 134, 153, 26, 37, 69, 90, 122, 27, 59, 91, 123, 28, 92, 124, 131, 156, 29, 93, 125, 30, 94, 126, 129, 158};
long col[58] = {0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff9900, 0xff9900, 0xff9900, 0xff9900, 0xff0000, 0xff9900, 0xff9900, 0xff0000, 0xff9900, 0xff9900, 0xff0000, 0xff0000, 0xff0000, 0xff9900, 0xff9900, 0xff9900, 0xff9900, 0xff0000, 0xff0000, 0xff9900, 0xff9900, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff9900, 0xff9900, 0xffff00, 0xffff00, 0x6aa84f, 0x6aa84f, 0x6aa84f, 0xffff00, 0xffff00, 0xffff00, 0xffff00, 0x6aa84f, 0xffff00, 0xffff00, 0xffff00, 0x6aa84f, 0xffff00, 0xffff00, 0x6aa84f, 0x6aa84f, 0x6aa84f, 0xffff00, 0xffff00, 0x6aa84f, 0xffff00, 0xffff00, 0x6aa84f, 0x6aa84f, 0x6aa84f};
int led_num = 58;
} (p_game);
struct {
int grid_pos[53] = {12, 13, 15, 19, 21, 24, 25, 29, 31, 34, 35, 39, 41, 44, 45, 49, 51, 54, 56, 58, 61, 64, 66, 68, 72, 73, 77, 92, 93, 94, 96, 97, 98, 102, 106, 108, 112, 116, 117, 118, 122, 123, 124, 126, 127, 132, 136, 138, 142, 143, 144, 146, 148};
int led_pos[53] = {46, 49, 81, 145, 18, 77, 82, 146, 19, 76, 83, 147, 20, 75, 84, 148, 21, 74, 106, 138, 22, 73, 105, 137, 40, 55, 119, 38, 57, 70, 102, 121, 134, 37, 101, 133, 36, 100, 123, 132, 35, 60, 67, 99, 124, 34, 98, 130, 33, 62, 65, 97, 129};
long col[53] = {0xffff00, 0xffff00, 0x6aa84f, 0x6aa84f, 0xffff00, 0xffff00, 0x6aa84f, 0x6aa84f, 0xffff00, 0xffff00, 0x6aa84f, 0x6aa84f, 0xffff00, 0xffff00, 0x6aa84f, 0x6aa84f, 0xffff00, 0xffff00, 0x6aa84f, 0x6aa84f, 0xffff00, 0xffff00, 0x6aa84f, 0x6aa84f, 0xffff00, 0xffff00, 0x6aa84f, 0x6fa8dc, 0x6fa8dc, 0x6fa8dc, 0xff00ff, 0xff00ff, 0xff00ff, 0x6fa8dc, 0xff00ff, 0xff00ff, 0x6fa8dc, 0xff00ff, 0xff00ff, 0xff00ff, 0x6fa8dc, 0x6fa8dc, 0x6fa8dc, 0xff00ff, 0xff00ff, 0x6fa8dc, 0xff00ff, 0xff00ff, 0x6fa8dc, 0x6fa8dc, 0x6fa8dc, 0xff00ff, 0xff00ff};
int led_num = 53;
} (p_over);
//------------------------------------------------------------------------------------------------------------------
//-------------------------------------GLOBALS----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------
// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(STRAND_LENGTH, LED_DATA_PIN, NEO_GRB + NEO_KHZ800);
//Interrupt Variables
volatile bool start = LOW;
//Button Variables
bool S = HIGH; //Square
bool T = HIGH; //Triangle
bool C = HIGH; //Circle
bool X = HIGH; //X
bool R1 = HIGH; //Right, upper Trigger
bool up = HIGH; //Up
bool down = HIGH; //Down
bool left = HIGH; //Left
bool right = HIGH; //Right
bool L1 = HIGH; //Left, upper Trigger
bool JR_B = HIGH; //Joystick R Button
bool JL_B = HIGH; //Joystick L Button
//Button_debounce
unsigned long db_left;
unsigned long db_right;
unsigned long db_fall;
unsigned long db_turn;
//Function-Variables
bool move_right = LOW;
bool move_left = LOW;
bool turn_r = LOW;
bool turn_l = LOW;
bool fall = LOW;
//Variables
byte adr = 0x08;
byte num = 0x00;
//Score Variables
int top_score = 0;
int score = 0;
const char row_multiplyer[]={0, 40, 100, 300, 1200}; //points you get dependending on how many rows are cleared
int level = 0; // level counter, will be multiplied with row_multiplyer
int previous_rows = 0;
bool pause_onece = false;
bool pause_pressed = false;
//Timer Variables
unsigned long t_draw_go = 0;
unsigned long t_score_disp = 0;
unsigned long previousMillis = 0;
unsigned long currentMillis = 0;
int pause_first_led = 0; //Für den Pause - Zyklus
// this is how arduino remembers what the button was doing in the past,
// so arduino can tell when it changes.
int old_button=0;
// so arduino can tell when user moves sideways
int old_px = 0;
// so arduino can tell when user tries to turn
int old_i_want_to_turn=0;
// this is how arduino remembers the falling piece.
int piece_id;
int piece_rotation;
int piece_x;
int piece_y;
// the bag from which new pieces are grabbed.
// the bag is only refilled when all pieces are taken.
// this guarantees a maximum of 12 moves between two Is
// or four S & Z in a row.
char piece_sequence[NUM_PIECE_TYPES];
char sequence_i=NUM_PIECE_TYPES;
// this controls how fast the player can move.
long last_move;
long move_delay; // 100ms = 5 times a second
// this controls when the piece automatically falls.
long last_drop;
long drop_delay; // 500ms = 2 times a second
long last_draw;
long draw_delay; // 60 fps
// this is how arduino remembers where pieces are on the grid.
long grid[GRID_W*GRID_H];
//------------------------------------------------------------------------------------------------------------------
//-------------------------------------INTERRUPT-FUNCTIONS----------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------
void i_start() { // Start/Pause Buttons
start = !start;
}
void i_awake() {
}
//------------------------------------------------------------------------------------------------------------------
//-------------------------------------Draw-Orders------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------
// I want to turn on point P(x,y), which is X from the left and Y from the top. // Angepasst
// I might also want to hold it on for us microseconds.
void p(int x,int y,long color) {
int a;
if( ( x % 2 ) == 0) { // % is modulus.
// y%2 is false when y is an even number - rows 0,2,4,6.
a = ((x+1) * GRID_H) -1;
a -= y;
} else {
// y%2 is true when y is an odd number - rows 1,3,5,7.
a = (x)*GRID_H;
a += y;
}
a%=STRAND_LENGTH; //Überlaufschutz
strip.setPixelColor(a,color);
}
// grid contains the arduino's memory of the game board, including the piece that is falling.
void draw_grid() {
int x, y;
for(y=0;y<GRID_H;y++) { //WIP
for(x=0;x<GRID_W;x++) {
if( grid[y*GRID_W+x] != 0 ) {
p(x,y,grid[y*GRID_W+x]);
}
else {
p(x,y,0);
}
}
}
strip.show();
}
void clear_strip() { //LED Streifen wird komplett auf 0 gesetzt
for(int i=0;i<STRAND_LENGTH;i++) {
strip.setPixelColor(i, strip.Color(0,0,0));
}
}
void draw_restart() { //Malt TETRIS auf den Bildschirm
for(int i=0;i<STRAND_LENGTH;i++)
{
strip.setPixelColor(i, strip.Color(0,0,0)); // Deletes the Board
}
for (int i = 0; i < p_tetris.led_num; i++){
strip.setPixelColor(p_tetris.led_pos[i],p_tetris.col[i]);
}
strip.show();
}
void draw_pause() //Schreibt PAUSE auf den Bildschirm
{
clear_strip();
for (int i = 0; i < p_pause.led_num; i++){
strip.setPixelColor(p_pause.led_pos[i],p_pause.col[i]);
}
strip.show(); // This sends the updated pixel color to the hardware.
if(!pause_onece)
{
pause_onece = true;
}
}
void all_white() //Schaltet alle LEDs auf Grün
{
for(int i=0;i<STRAND_LENGTH;i++){
strip.setPixelColor(i, strip.Color(120,120,120)); // Moderately bright green color.
strip.show(); // This sends the updated pixel color to the hardware.
delay(3); // Delay for a period of time (in milliseconds).
}
}
void game_over_loop_leds() //Wird beim Game over angezeigt
{
for(int i=0;i<STRAND_LENGTH;i++){
strip.setPixelColor(i, strip.Color(0,150,0));
strip.show(); // This sends the updated pixel color to the hardware.
delay(10); // Delay for a period of time (in milliseconds).
}
}
void draw_game_over() {
static bool game_over_text = false;
clear_strip();
if (game_over_text) {
for (int i = 0; i < p_over.led_num; i++){
strip.setPixelColor(p_over.led_pos[i],p_over.col[i]);
}
game_over_text = !game_over_text;
}
else {
for (int i = 0; i < p_game.led_num; i++){
strip.setPixelColor(p_game.led_pos[i],p_game.col[i]);
}
game_over_text = !game_over_text;
}
strip.show(); // This sends the updated pixel color to the hardware.
}
void pause_cyle(){
strip.setPixelColor(pause_first_led, strip.Color(255,0,0));
strip.show();
delay(500);
strip.setPixelColor(pause_first_led, strip.Color(0,0,0));
strip.show();
pause_first_led += GRID_H; //Springt in die nächste Zeile
if (pause_first_led > STRAND_LENGTH-1){
pause_first_led = 0;
}
delay(500);
}
//------------------------------------------------------------------------------------------------------------------
//-------------------------------------Game-Engine------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------
void try_to_drop_piece(bool player_action) { //Try to drop current piece one row down
erase_piece_from_grid();
if(piece_can_fit(piece_x,piece_y+1,piece_rotation)) {
piece_y++; // move piece down
add_piece_to_grid();
}
else {
// hit something!
// put it back
add_piece_to_grid();
remove_full_rows();
if(game_is_over()==1) {
game_over();
}
// game isn't over, choose a new piece
choose_new_piece();
}
}
// choose a new piece from the sequence.
// the sequence is a random list that contains one of each piece.
// that way you're guaranteed an even number of pieces over time,
// tho the order is random.
void choose_new_piece() {
if( sequence_i >= NUM_PIECE_TYPES ) {
// list exhausted
int i,j, k;
for(i=0;i<NUM_PIECE_TYPES;++i) {
do {
// pick a random piece
j = random(0, NUM_PIECE_TYPES);
// make sure it isn't already in the sequence.
for(k=0;k<i;++k) {
if(piece_sequence[k]==j) break; // already in sequence
}
} while(k<i);
// not in sequence. Add it.
piece_sequence[i] = j;
}
// rewind sequence counter
sequence_i=0;
}
// get the next piece in the sequence.
piece_id = piece_sequence[sequence_i++];
// always start the piece top center.
piece_y=-4; // -4 squares off the top of the screen.
piece_x=3;
// always start in the same orientation.
piece_rotation=0;
}
void remove_full_rows() {
int x, y, c;
char row_removed= 0;
int row_counter = 0;
for(y=0;y<GRID_H;++y) {
// count the full spaces in this row
c = 0;
for(x=0;x<GRID_W;++x) {
if( grid[y*GRID_W+x] > 0 ){
c++;
}
}
if(c==GRID_W) {
// row full!
delete_row(y);
fall_faster();
row_counter++; //contains total number of full rows after a draw
}
}
}
// Move everything down 1 space, destroying the old row number y in the process.
void delete_row(int y) {
int x;
for(;y>0;--y) {
for(x=0;x<GRID_W;++x) {
grid[y*GRID_W+x] = grid[(y-1)*GRID_W+x];
}
}
// everything moved down 1, so the top row must be empty or the game would be over.
for(x=0;x<GRID_W;++x) {
grid[x]=0;
}
}
void fall_faster() {
if(drop_delay > DROP_MINIMUM) drop_delay -= DROP_ACCELERATION;
}
// can the piece fit in this new location?
int piece_can_fit(int px,int py,int pr) {
if( piece_off_edge(px,py,pr) ) return 0;
if( piece_hits_rubble(px,py,pr) ) return 0;
return 1;
}
int piece_off_edge(int px,int py,int pr) {
int x,y;
const char *piece = pieces[piece_id] + (pr * PIECE_H * PIECE_W);
for(y=0;y<PIECE_H;++y) {
for(x=0;x<PIECE_W;++x) {
int nx=px+x;
int ny=py+y;
if(ny<0) continue; // off top, don't care
if(piece[y*PIECE_W+x]>0) {
if(nx<0) return 1; // yes: off left side
if(nx>=GRID_W ) return 1; // yes: off right side
}
}
}
return 0; // inside limits
}
int piece_hits_rubble(int px,int py,int pr) {
int x,y;
const char *piece = pieces[piece_id] + (pr * PIECE_H * PIECE_W);
for(y=0;y<PIECE_H;++y) {
int ny=py+y;
if(ny<0) continue;
for(x=0;x<PIECE_W;++x) {
int nx=px+x;
if(piece[y*PIECE_W+x]>0) {
if(ny>=GRID_H ) return 1; // yes: goes off bottom of grid
if(grid[ny*GRID_W+nx]!=0 ) return 1; // yes: grid already full in this space
}
}
}
return 0; // doesn't hit
}
//-------------------------------------GAME-OVER-----------------------------------------------------------------
// can the piece fit in this new location
int game_is_over() {
int x,y;
const char *piece = pieces[piece_id] + (piece_rotation * PIECE_H * PIECE_W);
for(y=0;y<PIECE_H;++y) {
for(x=0;x<PIECE_W;++x) {
int ny=piece_y+y;
int nx=piece_x+x;
if(piece[y*PIECE_W+x]>0) {
if(ny<0) return 1; // yes: off the top!
}
}
}
return 0; // not over yet...
}
void game_over() {
t_draw_go = millis();
start = true;
static bool display_state = true;
while (start) { //Runns until new game ist started
if (millis() >= t_draw_go + 2000) { //Switch between "GAME" and "OVER" display
draw_game_over();
t_draw_go = millis();
}
else{
}
}
score = 0;
setup();
return;
}
//-------------------------------------Player-Action----------------------------------------------------------------
void react_to_player() { //Choose which Action the Player wants to perform
erase_piece_from_grid(); //Erases the "old" form of the current piece from the grid array, while saving its coordinates
if (move_left || move_right){ //Are left / right buttons pushed?
try_to_move_piece_sideways();
}
if (turn_r) { //Is the rotate_r button pushed?
try_to_rotate_piece_r();
}
else if (turn_l){ //Or is the rotate_l button pushed?
try_to_rotate_piece_l();
}
add_piece_to_grid(); //Add adjusted piece back to the gird Array
if (fall){ //Drop current piece down
fall = LOW;
try_to_drop_faster();
}
}
void erase_piece_from_grid() { //Remove current piece from the grid array
int x, y;
const char *piece = pieces[piece_id] + (piece_rotation * PIECE_H * PIECE_W);
for(y=0;y<PIECE_H;++y) {
for(x=0;x<PIECE_W;++x) {
int nx=piece_x+x;
int ny=piece_y+y;
if(ny<0 || ny>GRID_H) continue;
if(nx<0 || nx>GRID_W) continue;
if(piece[y*PIECE_W+x]==1) {
grid[ny*GRID_W+nx]=0; // zero erases the grid location.
}
}
}
}
void try_to_move_piece_sideways() { //Move current piece sideways in memory
int new_px = 0;
if(move_left) {
new_px=-1;
move_left = LOW;
}
else if(move_right) {
new_px=1;
move_right = LOW;
}
if(new_px!=old_px && piece_can_fit(piece_x+new_px,piece_y,piece_rotation)==1) { //Checks if piece can still move in cosen direction
piece_x+=new_px;
}
//old_px = new_px;
}
void try_to_rotate_piece_r() { //Rotate the current piece right in memory
Serial.println("TRUNING RIGHT"); // DEBUG
// figure out what it will look like at that new angle
int new_pr = ( piece_rotation + 1 ) % 4;
if(piece_can_fit(piece_x,piece_y,new_pr)) {
// then make the turn.
piece_rotation = new_pr;
}
else {
// wall kick
if(piece_can_fit(piece_x-1,piece_y,new_pr)) {
piece_x = piece_x-1;
piece_rotation = new_pr;
} else if(piece_can_fit(piece_x+1,piece_y,new_pr)) {
piece_x = piece_x+1;
piece_rotation = new_pr;
}
}
}
void try_to_rotate_piece_l() { //Rotate the current piece left in memory
Serial.println("TRUNING LEFT"); // DEBUG
int new_pr = 0;
// figure out what it will look like at that new angle
if (piece_rotation == 0) {
new_pr = 3;
}
else {
new_pr = piece_rotation - 1;
}
if(piece_can_fit(piece_x,piece_y,new_pr)) {
// then make the turn.
piece_rotation = new_pr;
}
else {
// wall kick
if(piece_can_fit(piece_x-1,piece_y,new_pr)) {
piece_x = piece_x-1;
piece_rotation = new_pr;
} else if(piece_can_fit(piece_x+1,piece_y,new_pr)) {
piece_x = piece_x+1;
piece_rotation = new_pr;
}
}
}
void add_piece_to_grid() { //Add current piece to the grid array
int x, y;
const char *piece = pieces[piece_id] + (piece_rotation * PIECE_H * PIECE_W);
for(y=0;y<PIECE_H;++y) {
for(x=0;x<PIECE_W;++x) {
int nx=piece_x+x;
int ny=piece_y+y;
if(ny<0 || ny>GRID_H) continue;
if(nx<0 || nx>GRID_W) continue;
if(piece[y*PIECE_W+x]==1) {
grid[ny*GRID_W+nx]=piece_colors[piece_id]; // Value adds piece the grid location.
}
}
}
}
void try_to_drop_faster() { //Handels Drop Command
try_to_drop_piece(true);
}
//------------------------------------------------------------------------------------------------------------------
//-------------------------------------DEBUG------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------
//Prints the grid as debug to console
void grid_to_console() {
int x, y;
for(y=0;y<GRID_H-1;y++) { //WIP
for(x=0;x<GRID_W;x++) {
if( grid[y*GRID_W+x] != 0 ) {
Serial.print("x");
} else {
Serial.print(".");
}
}
Serial.print("\n");
}
Serial.print("------------------\n");
}
//Prints array to console
void print_grid() {
for (int i = 0; i < STRAND_LENGTH; i++) {
Serial.print(i);
Serial.print(": ");
Serial.println(grid[i]);
}
}
//------------------------------------------------------------------------------------------------------------------
//-------------------------------------SETUP------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------
void setup() {
Serial.begin(115200);
delay(1);
// setup the LEDs
strip.begin();
strip.show(); // Initialize all pixels to 'off'
// make sure arduino knows the grid is empty.
for(int i=0;i<GRID_W*GRID_H;i++) {
grid[i]=0;
}
// get ready to start the game.
choose_new_piece();
move_delay=INITIAL_MOVE_DELAY;
drop_delay=INITIAL_DROP_DELAY;
draw_delay=INITIAL_DRAW_DELAY;
db_right = db_left = db_turn = db_fall = millis();
// start the game clock after everything else is ready.
last_draw = last_drop = last_move = millis();
//print_grid();
draw_restart();
clear_strip();
strip.show();
}
//------------------------------------------------------------------------------------------------------------------
//-------------------------------------MAIN-------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------
// called over and over after setup()
void loop() {
long t = millis();
if(!start && !pause_pressed) {
//Passive Updates
//Actions
// the game plays at one speed,
if(t - last_move > move_delay ) {
last_move = t;
react_to_player();
}
// ...and drops the falling block at a different speed.
else if(t - last_drop > drop_delay ) {
last_drop = t;
try_to_drop_piece(false);
//grid_to_console(); //DEBUG
}
// when it isn't doing those two things, it's redrawing the grid.
else if(t - last_draw > draw_delay ) {
last_draw = t;
draw_grid();
}
}//end of pause_now
else if (start && !pause_pressed) { //Nachdem Pause betätigt wurde - Pause Bildschirm anzeigen
pause_pressed = true;
draw_pause();
}
else if (start && pause_pressed) { //Ladeanzeige während der Pause
pause_cyle();
}
else if (!start && pause_pressed) { //Nach erneutem betätigen: Bildschirm frei machen und fortfahren
pause_pressed = false;
clear_strip();
strip.show();
draw_grid();
}
}